Ser Programador

Como trabalhar com Orientação a Objetos no Adobe ColdFusion

Neste artigo vamos explorar o conceito por detrás do ColdFusion Component.


No ColdFusion os objetos são criados através dos Components. Estes por sua vez tem extensão .cfc, diferente da extensão .cfm comum aos demais arquivos de uma aplicação ColdFusion.


Para este artigo, vamos inicialmente imaginar um cenário onde você precise desenvolver um módulo que efetua cálculos matemáticos com as quatro principais operações matemáticas: soma, subtração, multiplicação e divisão.


Claro que como estamos falando de Orientação a Objetos, está fora de cogitação trabalhar com If ou Switch para identificar a operação e fazer o cálculo. Mesmo assim vou demonstrar o racional por detrás disso utilizando esses recursos para que possamos estar na mesma página sobre o objetivo deste exercício.

Vejamos então como ficaria a solução utilizando uma estrutura de If:

		<cfset resultado = "">

		<cfif form.operacao eq "soma">
			<cfset resultado = form.valor1 + form.valor2>
		</cfif>

		<cfif form.operacao eq "subtracao">
			<cfset resultado = form.valor1 - form.valor2>
		</cfif>

		<cfif form.operacao eq "multiplicacao">
			<cfset resultado = form.valor1 * form.valor2>
		</cfif>

		<cfif form.operacao eq "divisao">
			<cfset resultado = form.valor1 / form.valor2>
		</cfif>

		<cfoutput>
			O resultado da operação de #form.operacao# entre #form.valor1# e #form.valor2# é igual a #resultado#.
		</cfoutput>
	

Na linha 1 instanciamos um valor padrão para o resultado da operação;

Entre as linhas 3 e 17, trabalhamos o cálculo com os valores enviados pela requisição externa, de acordo com a operação também informada por essa requisição POST, modificando o valor da variável resultado com o resultado da operação;

Entre as linhas 19 e 21, apresentamos o resultado da operação em uma string de forma amigável, utilizando o resultado instanciado na linha 1 e modificado dentro dos IFs;

Para entender mais sobre os Operadores Condicionais, dê uma olhada NESTE ARTIGO;


Neste exemplo acima, se a operação for uma soma entre 15 e 19 o resultado será:

		O resultado da operação de soma entre 15 e 19 é igual a 34.
	


Se você é um pouco mais experiente com programação, sabe que uma sequência de IFs assim não é a maneira mais inteligente de se trabalhar com uma sequência de validações como essa.

Vejamos agora como ficaria a solução utilizando uma estrutura de Switch:

		<cfswitch expression="#form.operacao#">
		    <cfcase value="soma">
		    	<cfset resultado = form.valor1 + form.valor2>
		    </cfcase>
		    <cfcase value="subtracao">
		    	<cfset resultado = form.valor1 - form.valor2>
		    </cfcase>
		    <cfcase value="multiplicacao">
		    	<cfset resultado = form.valor1 * form.valor2>
		    </cfcase>
		    <cfcase value="divisao">
		    	<cfset resultado = form.valor1 / form.valor2>
		    </cfcase>
		    <cfdefaultcase>
		    	<cfset resultado = "">
		    </cfdefaultcase>
		</cfswitch>

		<cfoutput>
			O resultado da operação de #form.operacao# entre #form.valor1# e #form.valor2# é igual a #resultado#.
		</cfoutput>
	

Nosso código neste exemplo faz a mesma coisa que o anterior, mas de forma mais profissional, e inclusive performática na execução do programa;

Para entender mais sobre o funcionamento do Switch, dê uma olhada NESTE ARTIGO;


Agora sim, podemos mentalizar como escrever nosso Component, baseado nessa lógica de funcionamento do sistema. Primeiro precisamos criar um novo arquivo, que chamaremos de calcular.cfc. Dentro dele colocaremos a estrutura básica de um Component:

		<cfcomponent>
		</cfcomponent>
	

Agora vamos instanciar o objeto desse Component em nosso arquivo principal:

		<cfset calcular = createObject("component", "calcular")>
	

Ao passar component para o primeiro parâmetro de calcular para o segundo, o ColdFusion sabe que buscar um arquivo calcular.cfc no mesmo diretório;


Se você estiver utilizando outro diretório para guarar os Components, você deve fornecer o caminho relativo a partir do diretório atual até o arquivo do Component. Por exemplo, imagine que esteja utilizando um diretório chamado componentes que está no mesmo diretório do arquivo principal. Então teríamos:

		<cfset calcular = createObject("component", "componentes/calcular")>
	

Tenha em mente que o diretório componentes não pode estar estar em um nível acima, pois ao fornecer "../componentes/calcular" o ColdFusion retornará um erro do tipo: name is not a valid component or interface name;



Agora que sabemos que o ColdFusion conseguiu carregar nosso component, vamos criar os métodos das operações no arquivo calcular.cfc:

		<cfcomponent>
			<cffunction name="soma" access="public">
				<cfreturn arguments.valor1 + arguments.valor2>
			</cffunction>
			<cffunction name="subtracao" access="public">
				<cfreturn arguments.valor1 - arguments.valor2>
			</cffunction>
			<cffunction name="multiplicacao" access="public">
				<cfreturn arguments.valor1 * arguments.valor2>
			</cffunction>
			<cffunction name="divisao" access="public">
				<cfreturn arguments.valor1 / arguments.valor2>
			</cffunction>
		</cfcomponent>
	

Note que a estrutura está bem parecida com a do Switch;

Utilizamos a Struct arguments, criada automaticamente pelo ColdFusion ao ser fornecido qualquer argumento no momento de requisitar o método do Component;

Utilizamos o cfreturn para retornar o resultado da operação, em cada um dos métodos criados;


Agora já podemos chamar os métodos do nosso objeto, no arquivo principal onde instanciamos o objeto. Vamos testar inicialmente com a soma:

		<cfset calcular = createObject("component", "componentes/calcular")>
		<cfset resultado = calcular.soma(valor1 = form.valor1, valor2 = form.valor2)>

		<cfoutput>
			O resultado da operação de soma entre #form.valor1# e #form.valor2# é igual a #resultado#.
		</cfoutput>
	

Observe como passamos os parâmetros valor1 e valor2 como argumentos para o método soma;


Se tudo estiver correto, e os valores valor1 e valor2 são respectivamente 25 e 14 o resultado será:

		O resultado da operação de soma entre 15 e 19 é igual a 39.
	


Vamos implementar agora a identificação da operação e o cálculo sendo feito chamando o método específico:

		<cfset calcular = createObject("component", "componentes/calcular")>

		<cfswitch expression="#form.operacao#">
		    <cfcase value="soma">
		    	<cfset resultado = calcular.soma(valor1 = form.valor1, valor2 = form.valor2)>
		    </cfcase>
		    <cfcase value="subtracao">
		    	<cfset resultado = calcular.subtracao(valor1 = form.valor1, valor2 = form.valor2)>
		    </cfcase>
		    <cfcase value="multiplicacao">
		    	<cfset resultado = calcular.multiplicacao(valor1 = form.valor1, valor2 = form.valor2)>
		    </cfcase>
		    <cfcase value="divisao">
		    	<cfset resultado = calcular.divisao(valor1 = form.valor1, valor2 = form.valor2)>
		    </cfcase>
		    <cfdefaultcase>
		    	<cfset resultado = "">
		    </cfdefaultcase>
		</cfswitch>

		<cfoutput>
			O resultado da operação de #form.operacao# entre #form.valor1# e #form.valor2# é igual a #resultado#.
		</cfoutput>
	

Pronto! Temos nosso sistema de cálculo funcionando perfeitamente!

Será mesmo?


Essa estrutura com Switch cabe muito bem quando a expressão validada nos cases é diferente dos nomes dos métodos chamados dentro desses cases.

Note que o valor checado pela expressão do Switch nos cases é exatamente o mesmo que estabelecemos como os nomes dos métodos do nosso Component. Quando isso acontece (e trabalhamos para que isso aconteça ao desenvolver sistemas com uso de Orientação a Objetos), nós podemos simplificar muito o código com o uso da função Evaluate, do próprio ColdFusion.


Vamos aplicar o Evaluate no nosso arquivo principal:

		<cfset calcular = createObject("component", "componentes/calcular")>

		<cfset resultado = Evaluate("calcular.#form.operacao#(valor1 = form.valor1, valor2 = form.valor2)")>

		<cfoutput>
			O resultado da operação de #form.operacao# entre #form.valor1# e #form.valor2# é igual a #resultado#.
		</cfoutput>
	

Sim, nós substituímos o Switch inteiro por uma só linha de código!

Note que para isso nós somente passamos como argumento para o Evaluate a chamada do método do nosso objeto, em forma de string, substituindo o nome do método pela "variável" form.operacao, que já traz naturalmente o nome do método que precisamos chamar.

Ao desenvolver dessa forma, o único trabalho que você teria é checar se a operação presente em form.operacao é uma operação válida para que o ColdFusion não retorne um erro do tipo: The method was not found in component.


Vamos validar as operações:

		<cfset calcular = createObject("component", "componentes/calcular")>

		<cfset operacoesValidas = ['soma', 'subtracao', 'multiplicacao', 'divisao']>
		<cfif ArrayContains(operacoesValidas, form.operacao)>
			<cfset resultado = Evaluate("calcular.#form.operacao#(valor1 = form.valor1, valor2 = form.valor2)")>
			<cfoutput>
				O resultado da operação de #form.operacao# entre #form.valor1# e #form.valor2# é igual a #resultado#.
			</cfoutput>
		<cfelse>
			<cfoutput>Operação inválida</cfoutput>
		</cfif>
	

Prontinho! Nosso código está plenamente funcional!

Utilizamos um array operacoesValidas contendo as operações que são válidas;

Utilizamos a função ArrayContains, fornecendo o array com operacoesValidas e form.operacao, para que assim possamos saber se a operação informada pela requisição está dentre as operações que nosso objeto trabalha;


Se você quiser ser um pouco mais profissional, você pode utilizar a função getmetadata, e fazer um LOOP no item functions existente na struct retornada como resultado dessa função, para assim construir o array com os nomes dos métodos existentes no objeto. Dessa forma você fica isento de sempre atualizar o array operacoesValidas manualmente, cada vez que um novo método for criado no objeto.

Vamos implementar isso:

		<cfset calcular = createObject("component", "componentes/calcular")>

		<cfset funcoesDoObjeto = getmetadata(calcular).functions> 

		<cfset operacoesValidas = []>
		<cfloop array="#funcoesDoObjeto#" index="function">
			<cfset arrayAppend(operacoesValidas, function.name)>
		</cfloop>

		<cfif ArrayContains(operacoesValidas, form.operacao)>
			<cfset resultado = Evaluate("calcular.#form.operacao#(valor1 = form.valor1, valor2 = form.valor2)")>
			<cfoutput>
				O resultado da operação de #form.operacao# entre #form.valor1# e #form.valor2# é igual a #resultado#.
			</cfoutput>
		<cfelse>
			<cfoutput>Operação inválida</cfoutput>
		</cfif>
	

Na linha 3, coletamos os metadados do objeto calcular com uso da função getmetadata, e guardamos na variável funcoesDoObjeto o array com os dados existentes em functions;

Na linha 5, instanciamos um novo array vazio operacoesValidas, para guardar nele os nomes dos métodos existentes no objeto calcular;

Na linha 6, fazemos um loop no array funcoesDoObjeto, e assim, para cada item desse array, fazemos um append no array operacoesValidas, alimentando-o com os nomes dos métodos;


Não esqueça de sempre validar se os valores recebidos estão no formato esperado, e efetuar um cast desses valores. Neste caso, certifique-se de que os valores recebidos são numéricos, e converta-os para tipos numéricos, evitando assim que o método do cálculo receba uma string e acabe terminando a execução num erro.


Maravilha! Agora você já domina a Orientação a Objetos no ColdFusion e certamente escreverá sistemas de forma muito mais profissional!