Boa tarde,
Alguém tem um exemplo de como implementar o pattern Singleton em uma classe advpl?
Acontece que estou tendo que dar um MinhaClasse:NEW() dentro de um laço de repetição para não repetir os atributos da instância.
Se alguma pergunta ou resposta lhe foi útil, não deixe de dar seu voto positivo!
Boa tarde,
Alguém tem um exemplo de como implementar o pattern Singleton em uma classe advpl?
Acontece que estou tendo que dar um MinhaClasse:NEW() dentro de um laço de repetição para não repetir os atributos da instância.
Atualmente na linguagem ADVPL não é possível implementar o padrão de projeto Singleton, dado ao fato que é necessário que a propriedade que armazenará a instância da classe tenha escopo privado (assim como o construtor), contudo o ADVPL não possui identificadores de escopo de privem o usuário do acesso direto.
Ainda não tem escopo em métodos e atributos. Mas no lobo guará isto será possível.
— Jandir Deodato 03 de Oct de 2018Sim! Diferente do que muitos pensam, em AdvPL, uma classe não possui um método construtor padrão; e a palavra chave Constructor
serve apenas para legibilidade.
Classe():Metodo()
, independente do método estar assinado como construtor, sempre é criada uma instância nova.obj:Metodo()
, localiza-se a o protótipo da classe de objeto, então invoca-se o método com o valor de Self
predefinido como a instância atual.Podemos usar variáveis estáticas para reter uma instância de classe e implementar o New
definindo a instância inicial da classe e sempre retornando-a.
Situação similar acontece quando herdamos de uma classe sem sobrecarregar o New
: uma instância da classe pai é retornada.
Para instanciar a primeira vez, podemos usar a função WsClassNew
. Nas versões recentes dos includes TOTVS, em específico, o msobject.ch
, há a implementação da cláusula Static
para métodos, então podemos ter singletons:
/** HERE BE DRAGONS */
#include 'protheus.ch'
Static oInstance
Class MySingleton
Static Method New()
EndClass
Method New() Class MySingleton
If oInstance == Nil
oInstance := WsClassNew( 'MySingleton' )
EndIf
Return oInstance
User Function Singleton()
Local oInstance := MySingleton():New()
Local oOther := MySingleton():New()
If oInstance == oOther
ConOut( "References are equal!" )
Else
ConOut( "Nope!" )
EndIf
Return
Solução muito boa! Mas é uma solução de contorno, pois você não está retornando os dados providos da classe, mas sim da chamada de uma função externa para o objeto oInstance
.
Atende ao requisito de sempre trabalhar com a mesma referência de objeto, todavia não é realmente Singleton.
— Guilherme Bigois 22 de Oct de 2018Uma maneira de privatizar o construtor é verificar a existência de instância e, já havendo uma, lançar uma exceção (já que em linguagens dinâmicas a visibilidade de propriedades não é decidível em tempo de compilação).
— Marcelo Camargo 23 de Oct de 2018