Singleton em ColdFusion

On 2 de março de 2012, in CFML, Desenvolvimento, Design Pattern, by andersonstraube

Singleton, é um padrão de projeto de software (do inglês Design Pattern). Este padrão garante a existência de apenas uma instância de uma classe, mantendo um ponto global de acesso ao seu objeto.
O termo vem do significado em inglês quando se resta apenas uma carta nas mãos, num jogo de baralho.
Muitos projetos necessitam que algumas classes tenham apenas uma instância. Por exemplo, em uma aplicação que precisa de uma infraestrutura de log de dados, pode-se implementar uma classe no padrão singleton. Desta forma existe apenas um objeto responsável pelo log em toda a aplicação que é acessível unicamente através da classe singleton.
Fonte: http://pt.wikipedia.org/wiki/Singleton

A maioria das classes/instâncias do ColdFusion (CFC) podem ser transformadas em um singleton, vamos ver como isso funciona na prática:

Vamos criar o Application.cfc responsável por manter o escopo persistente:


<cfcomponent output="false">


	<cfscript>
		this.name              = "Teste";
		this.applicationTimeout = CreateTimeSpan(0,4,0,0);
	</cfscript>

	<!--- Ao iniciar a aplicação carrega as variáveis persistentes --->
	<cffunction name="onApplicationStart" access="public" returntype="void" output="false">
		<cfset this.reloadApp() />
	</cffunction>


	<cffunction name="onRequestStart" access="public" returntype="boolean" output="true">
		<cfargument name="targetPage" type="string" required="true" />

		<!--- Criamos um identificador para reiniciar nossas classes que estão no escopo persistente --->
		<cfif isDefined("URL.init") >
			<cfset this.reloadApp() />
		</cfif>

		<cfreturn true />
	</cffunction>


	<cffunction name="reloadApp" access="private" output="false" returntype="void">

		<cflock scope="application" timeout="30" type="exclusive">
			<cfset application.factory = CreateObject( "component", "factory" ).init() />
		</cflock>

	</cffunction>

</cfcomponent>

Na linha 27 ( <cfset application.factory = CreateObject( "component", "factory" ).init() /> ) instanciamos nossa factory no escopo persistente, essa será a classe responsável pela criação dos objetos.

O padrão Factory fornece uma interface para a criação de famílias de objetos correlatos ou dependentes sem a necessidade de especificar a classe concreta destes objetos.

factory.cfc


<cfcomponent displayname="factory">


  <cffunction name="init" access="public" output="false" returntype="factory">

    <cfscript>
	  variables.instance  = structNew();
    </cfscript>

    <cfreturn this />
  </cffunction>


  <cffunction name="getInstance" access="public" output="false" returntype="any">
    <cfargument name="name" type="string" required="true" >

    <cfscript>
      // Verifica se a instancia já foi carregada, caso contrário cria a instancia do objeto
      if ( not StructKeyExists(variables.instance, arguments.name) ){
          variables.instance[ arguments.name ] = createInstance( arguments.name );
      }

      return variables.instance[ arguments.name ];
    </cfscript>

  </cffunction>


  <cffunction name="createInstance" access="private" output="false" returntype="any">
    <cfargument name="name" type="string" required="true" >

    <cfscript>
      switch( arguments.name ) {

		  case "Util":
              return CreateObject( "component", "Util" ).init();
              break;

		  // aqui você coloca a implementação ou mapeamento dos seus componentes da forma que achar melhor
          case "Cliente":
              return CreateObject( "component", "cfc.mapping.Cliente" ).init();
              break;
      }
    </cfscript>

  </cffunction>

</cfcomponent>>

Para este exemplo eu deixei o Util.cfc na mesma pasta para fins de teste, porém em um sistema real é interessante que os componentes estejam organizados em pastas e com o mapping correspondente.

Agora vamos criar nosso componente de teste que ficará em singleton, ou seja, terá apenas uma instância deste objeto em toda a aplicação.

Util.cfc


<cfcomponent displayname="Util">

  <cffunction name="init" access="public" output="false" returntype="Util">

	<cfreturn this />
  </cffunction>


  <cffunction name="somenteNumeros" access="public" output="false" returntype="string">
	<cfargument name="conteudo" type="string" required="true"/>

	<cfreturn REReplace( arguments.conteudo, "[^[:digit:]]", "", "all" ) />
  </cffunction>

</cfcomponent>

Por fim vamos a implementação das chamadas do nosso componente.

teste.cfm


<cfset variables.util = application.factory.getInstance("Util") />

<cfoutput>#variables.util.somenteNumeros("a1b2c3d4e5f6g7")#</cfoutput>

Como podemos ver é muito simples implementar o padrão Singleton em suas aplicações. A complexidade aumenta ao gerenciar as dependências entre objetos e instanciar os objetos somente quando necessário.

Tagged with:  

6 Responses to Singleton em ColdFusion

  1. Anderson, muito bom o artigo.

    Fazer uso de Singleton usando Factory realmente é uma solução bem legal…

    Eu sempre opto pelo simplão, tenho um método no application que se não fez a instância dos objetos ele faz, caso contrário não faz novamente. Mas isso gera o problema de que todos os objetos sejam criados de uma só vez!

    Usando Factory você vai fazendo por demanda.

    Muito bom, parabéns pelo artigo.

    Grande abraço

    • andersonstraube disse:

      Realmente o uso do Factory ajuda em muito, principalmente na questão da organização do código e também a criação dos objetos sob demanda.
      Obrigado pela leitura e principalmente pelo comentário Paulo.

      Abraço.

  2. […] Singleton em ColdFusion Compartilhe isso:EmailFacebook Se você gostou deste artigo, por favor compartilhe […]

  3. […] Singleton em ColdFusion – Observer Pattern em […]

  4. […] ou objetos. Uma das grandes vantagens em utilizar objetos literais é a possibilidade de usarmos Singleton uma vez que esses objetos não podem ser […]

  5. […] Singleton em ColdFusion – Observer Pattern em ColdFusion – Strategy Pattern em […]

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *