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.
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