Dois métodos de implementação do modo Singleton em Delphi
haozi
Resumo Este artigo descreve duas implementações Delphi do modo Singleton e faz uma análise comparativa.
Padrão de design de palavras-chave, Singleton
O padrão Singleton é um padrão de design muito útil. Sua intenção é simplesmente criar uma instância de uma classe e fornecer um ponto de acesso global para ela. Variáveis globais tornam um objeto facilmente acessível, mas não impedem que você instancie vários objetos. O objetivo do padrão singleton é garantir que exista apenas uma instância durante o ciclo de vida do programa.
Veja o código abaixo:
Procedimento TForm1.Button1Click(Remetente: TObject);
var lS1 : TSingleton;
S2: TSingleton;
começar
tente lS1 := TSingleton.Create; ////Chama o construtor da classe
lS2 := TSingleton.Create; ////Chama o construtor da classe
//// ...outro código
finalmente
lS1.Free; ////Libere o objeto
lS2.Free; ////Libere o objeto
fim;
fim;
No código acima, a classe TSingleton é instanciada quando a função Create é chamada pela primeira vez. lS1 aponta para o endereço de um objeto de armazenamento de memória. Quando a função TSingleton.Create é chamada pela segunda vez, o objeto TSingleton é re. -instanciado. lS2 aponta para o endereço alocado na memória. O padrão Singleton permite que a própria classe seja responsável por salvar sua única instância.
No código acima, quando ls2 é criado, ele também aponta para o objeto apontado por ls1 (ou seja, é alocado o mesmo endereço de memória. Da mesma forma, devemos evitar que a memória seja liberada ao liberar ls1, pois o único). object também é referenciado por ls2. Isso garante que haja apenas uma instância de classe durante o ciclo de vida do programa.
O código de amostra de C++ em "Design Pattern" usa variáveis de membro estático C++ para salvar instâncias e usa funções de construtor protegidas. No entanto, como não existem variáveis de membro estáticas no Delphi, o método deste exemplo de modo singleton não pode ser usado como está. Abaixo analisamos várias maneiras de o DELPHI implementar o modo Singleton.
um. Método baseado na substituição de duas funções virtuais do Tobject
função de classe NewInstance: TObject virtual;
procedimento FreeInstance virtual;
A função NewInstance é responsável por alocar memória para o objeto quando o objeto da classe é criado, enquanto FreeInstance libera a memória ao contrário.
.
O primeiro é chamado quando o objeto é construído e o último é chamado quando o objeto é destruído.
Usamos duas variáveis globais para armazenar o objeto singleton e a contagem de referência do objeto.
varInstance: TSingleton = nil;
ContaRef: Inteiro = 0;
Unidades da classe TSingleton:
////--------------------------------------------------------- ----------------------------
////
unidade uSingleton;
interface
tipo
TSingleton = classe(TObject)
público
função de classe NewInstance: TObject override; ////Substituir função de classe base
procedimento FreeInstance; override; ////Substituir função da classe base
class function RefCount: Integer;////Retorna a contagem de referência atual
fim;
//// Variáveis globais de declaração
var
Instância: TSingleton = nulo;
ContagemRef: Inteiro = 0;
implementação
{TSingleton}
procedimento TSingleton.FreeInstance;
começar
Dec( RefCount );////Diminui a contagem de referência
if (RefCount = 0) então ////É 0, se sim, libere a memória
começar
Instância := nulo;
//// Libera as variáveis privadas da classe singleton
////…
FreeInstance herdada;
fim;
fim;
função de classe TSingleton.NewInstance: TObject;
começar
if (não atribuído (instância)) então
começar
Instância: = TSingleton (herdado NewInstance);
////Exemplo de inicialização de variáveis privadas:
//// Instance.VariableName := Valor;
fim;
Resultado := Instância ;
Inc(ContRef);
fim;
função de classe TSingleton.RefCount: Integer;
começar
Resultado := RefCount;
fim;
fim.
////--------------------------------------------------------- ----------------------------
////
Quando o construtor de TSingleton for chamado, nossa função de substituição NewInstance será chamada e NewInstance alocará memória e a retornará ao construtor. Desta forma, por meio da função de substituição NewInstance, garantimos que a função Create só pode instanciar um objeto TSingleton. (não importa quantas vezes seja chamado) Create retorna apenas o endereço de memória alocado pela primeira vez). Ao mesmo tempo, a variável RefCount contém quantas referências temos ao objeto.
Vejamos o código de teste
procedimento TForm1.Button1Click(Remetente: TObject);
var
lS1, lS2: TSingleton;
Ob1, Ob2: Objeto;
começar
lS1 := TSingleton.Create;
ShowMessage(IntToStr(RefCount)); //// Ref_Count = 1
lS2 := TSingleton.Create;
ShowMessage(IntToStr(RefCount)); //// Ref_Count = 2
Ob1 := TObject.Create;
Ob2 := Tobject.Create;
se lS1 = lS2 então
ShowMessage('Endereços são iguais') //// lS1 = lS2
outro
ShowMessage('Endereços não são iguais');
se Ob1 = Ob2 então
ShowMessage('Endereços são iguais')
outro
ShowMessage('Endereços não são iguais'); //// Ob1 <> Ob2
fim;
Quando o programa chama o destruidor (ou seja, quando a função FREE é chamada), o destruidor chama a função FreeInstance para liberar a memória alocada pelo construtor. A função FreeInstance de Override garante que a memória do objeto do modo singleton seja liberada somente quando a contagem de referência atingir zero.
Aqui está nosso código de teste:
var
lS1: TSingleton;
lS2: TSingleton;
começar
tentar
lS1 := TSingleton.Create; ////Chama o construtor da classe
lS2 := TSingleton.Create; ////Chama o construtor da classe
//// ...outro código
finalmente
lS1.Free; ////Aqui chamaremos primeiro o FreeInstance definido por nossa substituição,
////Como RefCount é 1 após decrementar 1 neste momento, o objeto singleton não foi liberado.
lS2.Free; ////dec(RefCount)= 0 libera o objeto singleton
fim;
fim;
O método de implementação do padrão singleton acima é uma boa maneira de perceber que a própria classe é responsável por salvar sua própria instância única (interceptando a solicitação para criar um novo objeto - consulte "Padrões de Design". Ele não tem restrições especiais sobre o uso da classe TSingleton - —Os programadores podem chamar as funções Create e Free à vontade.
A desvantagem deste modo é que a classe TSingleton não pode ser herdada como classe pai para gerar subclasses. Se a herança gerar duas subclasses, apenas um objeto será gerado durante a criação.
procedimento TForm1.Button1Click(Remetente: TObject);
var
lS1: subcategoria um;
IS2: subcategoria dois;
começar
lS1 := Subclasse 1.Criar;
lS2 := Subclasse 2.Create; ////A subclasse 2 não será criada, lS2 apontará para a memória apontada por lS1,
////Isto é, lS1 = lS2end;
dois. Implementação Delphi do exemplo em "Design Patterns"
O exemplo de implementação de "Design Pattern" é controlar apenas uma instância de objeto por meio de uma função construtora privada. No entanto, a implementação do código C++ fornecida não fornece como o objeto é lançado. A função Create não pode ser privatizada no Delphi. Definimos uma nova função para substituir a função Create e proteger a função Create da classe pai. O código é o seguinte
:
////--------------------------------------------------------- ----------------------------
////
unidade uSingletonUnit;
interface
usa
Classes, SysUtils;
tipo
TCSingleton = class(TComponent) ////Herdado da classe Tcomponent.
privado
construtor CreateInstance(AOwner: TComponent); ////Passe o parâmetro Owner
//// Desta forma, o objeto da classe TCSingleton será destruído junto com o Owner (o proprietário é responsável por destruir o objeto TCSingleton)
público
construtor Criar (AOwner: substituição de TComponent);
função de classe Instância (AOwner: TComponent): TCSingleton;
fim;
var
gCSingleton: TCSingleton; //// Variáveis globais
implementação
{TCSingleton}
construtor TCSingleton.Create(AOwner: TComponent);
começar
////Proteja a função da função Criar
raise Exception.CreateFmt('classe de acesso %s somente através da instância',
[Nome da Classe]);
fim;
construtor TCSingleton.CreateInstance(AOwner: TComponent);
começar
////O construtor recém-definido é Privado
herdado Criar (AOwner);
fim;
função de classe TCSingleton.Instance(AOwner: TComponent): TCSingleton;
começar
se não for atribuído (gCSingleton), então
gCSingleton := TCSingleton.CreateInstance(AOwner);
Resultado: = gCSingleton;
fim;
fim.
////--------------------------------------------------------- --------------------------------------------/
/
Durante o uso da classe de implementação acima, os programadores não precisam considerar a destruição de objetos no modo singleton. Ele simplesmente não pode chamar Create, você deve chamar a função Instance para obter uma instância do objeto e passar o proprietário do singleton como parâmetro para a função. Este método de implementação pode ser herdado como uma classe base e usado em um singleton do padrão de estado (consulte a Referência 4) para obter polimorfismo em tempo de execução.
três. Conclusão
A implementação Delphi do modo Singleton também pode ser encontrada na Internet. Existem outros métodos de implementação.
O mais comum e simples. Ao mesmo tempo, as ideias de outros métodos também são muito semelhantes aos dois métodos acima.