POO: Objetos quot;Auto-instanciáveisquot;

Delphi

07/09/2009

Olá todos, o objetivo deste post é colocar uma alternativa *real* ao artigo de mesmo título publicado na ClubeDelphi número 109.


Primeiramente, quero colocar que criar objetos na inicialização da aplicação é algo que deve ser feito com critério, uma vez que memória é alocada consumindo recursos, isto deve ser realizado apenas quando necessário (para objetos que realmente precisamos ´instanciados´ desde sempre)

Geralmente quando precisamos destes objetos sem ter que nos preocupar com sua inicialização, estes são objetos ´centrais´ que possuem uma única instância para ser utilizada por toda aplicação. Por isso, e apenas para estes casos, posto a seguir um código exemplo utilizando o padrão de projeto Singleton.

Nesta implementação o objeto não é ´instanciado´ na seção Initialization, mas sim APENAS quando for usado pelo primeira vez, em qualquer parte da aplicação. Vamos ao código:



unit MeuObjeto;

uses
  SysUtils, Classes;

type

  TMeuObjeto = class (TObject)
  private
    fNome: string;
    fLista: TStrings;
  public
    constructor Create;
    destructor Destroy; override;
    class function Instance: TMeuObjeto;
    property Nome: string read fNome write fNome;
    property Lista: TStrings read fLista;
  end;


  function MeuObjeto: TMeuObjeto;

implementation

var
  InstanciaMeuObjeto: TMeuObjeto = nil;


function MeuObjeto: TMeuObjeto;
begin
  Result := TMeuObjeto.Instance;
end;


constructor TMeuObjeto.Create;
begin
  inherited Create;
  fLista := TStringList.Create;
  fNome := ´´;
end;

destructor TMeuObjeto.Destroy;
begin
  fLista.Free;
  inherited;
end;

class function TMeuObjeto.Instance: TMeuObjeto;
begin
  if InstanciaMeuObjeto=nil then
    InstanciaMeuObjeto := TMeuObjeto.Create;
  Result := InstanciaMeuObjeto;
end;

initialization

finalization
  if InstanciaMeuObjeto<>nil then
    InstanciaMeuObjeto.Free;

end.


Comentários sobre o código:

Note que foi criada uma FUNÇÃO como ponto de acesso global a instância do objeto e não uma variável. Isto garante maior poder e controle sobre a inicialização e destruição da mesma. Exemplo: Mesmo que um programador ´desavisado´ em determinado momento chame:

MeuObjeto.Free;

na próxima chamada de MeuObjeto ele estará lá novamente (uma nova instância, claro -- mas não haverá uma exceção de violação de acesso de memória)

Mas principalmente, função permite que o objeto seja criado APENAS quando for chamado pela primeira vez (e não na inicialização do programa, como ocorre com código da inicialization)

Outro ponto importante de notar é que a ´variável´ que contém a instância de nosso objeto fica em IMPLEMENTATION garantindo assim que nenhuma outra unit possa acessá-la diretamente (garantindo encapsulamento)

Ainda, a criação do método de classe ´Instance´ é opcional. Seu código poderia estar direto na função de entrada ´MeuObjeto´, caso não desejasse ter o método de classe. No exemplo acima:

TMeuObjeto.Instance.Nome := ´Teste´;

é igual a

MeuObjeto.Nome := ´Teste´;


Por fim, é importante notar que o destructor da classe foi re-escrito para destruir o objeto fLista criado no constructor, e que a seção finalization foi escrita para garantir que uma vez que InstanciaMeuObjeto tenha sido criado, seja destruído ao final da aplicação.

Vale salientar que este mesmo padrão pode ser implementado para Forms e DataModules (ou qualquer outra classe).


Vou ficando por aqui, esperando ter sido útil de alguma forma. Abraços a todos.

Anderson


Afarias

Afarias

Curtidas 0

Respostas

Osocram

Osocram

07/09/2009

Minha revista ainda não chegou :(

Não tenho o costume de usar o Initialization e o Finalization para instanciar ou destruir objetos, E sim para registrar Classes.

Mas assim que minha revista chegar, vou dar uma olhada no artigo p discutir melhor.


GOSTEI 0
Afarias

Afarias

07/09/2009

Aguarde e confie ;-)


GOSTEI 0
Osocram

Osocram

07/09/2009

Amigo...
Recebi hj a minha revista, apenas com alguns dias de atraso.

Bom particularmente não gosto desse tipo de abordagem.

O que geralmente gosto, e estou tentando fazer nos sistema é que cada Objeto meu saiba se criar e se destruir.

Por exemplo meu sistema é MDI, mas as vezes tenho que usar alguns form SDI (não MDI) então qdo é assim eu criei uma classe no qual fiz uma ´Método de Classe´ geralmente .Execute; no qual faz o create do form e como é showmodal logo apos isso ele mesmo ja se destroi.
Ficando apenas assim a chamada do mesmo.
TMeuFormSDI.Execute;


Mas se for ver apenas estamos aplicando diferentemente os mesmos recursos que eles mostraram na materia.

Aquilo que colocaram deve ser usado com cautela. eu so vi uma aplicação para aquilo, até o momento, que seria para criar uma classe de usuario no sistema que ao logar eu guardaria todos os privilegios.
Mas nada impediria de eu criar isso no braço tbm usando um metodo Execute.


GOSTEI 0
Afarias

Afarias

07/09/2009

|Mas se for ver apenas estamos aplicando diferentemente os mesmos
|recursos que eles mostraram na materia.

Não vejo bem por ai...


|Aquilo que colocaram deve ser usado com cautela.

Na minha modesta opnião, não deve ser usado de jeito nenhum. Além do problema conceitual, os códigos exemplo estão cheios de falhas como memory leaks, etc.


|eu so vi uma aplicação para aquilo, até o momento, que seria para criar
|uma classe de usuario no sistema que ao logar eu guardaria todos os
|privilegios.

Para isso servem os Singletons como no exemplo q mostrei.

A implementação de o singleton que dei de exemplo pode até não parecer muito diferente do código da matéria, mas tem detalhes q dão uma diferença muito grande se observados com cuidado -- tanto a nível conceitual quanto de implementação.


|Mas nada impediria de eu criar isso no braço tbm usando um metodo
|Execute.

Gosto desta abordagem e tb utilizo. Mas existem classes q são manipuladas, trocam informações, etc, onde esta abordagem não se aplica.

Neste caso que vc citou, vc cria um método de classe q encapsula uma ação completa -- criação da instancia, execução de uma tarefa e destruição!

Isto vai além da questão de inicialização de objetos (como uso de padrões singleton, factories, etc) -- e o método é específico para uma tarefa.


T+


GOSTEI 0
Wdrocha

Wdrocha

07/09/2009

Concordo plenamente com o colega Afarias, raramente existe uma razão para instanciar um objeto no Inicialization, pois manter mts objetos enquanto a aplicação está sendo executada pode ser mt caro quando não se tem a real necessidade disso.


E para que os colegas do fórum entendam melhor o q ele falow sobre o Singleton, ele é um padrão de projeto utilizado quando queremos apenas uma única instância de algum objeto.


Este é apenas um dos muitos padrões utilizados hj no mercado, existem mts outros, quem não conhece seria uma boa pesquisar e ler um pouco sobre Padrões de Projetos.



fica aew a dica...


flw


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

Na minha modesta opnião, não deve ser usado de jeito nenhum. Além do problema conceitual, os códigos exemplo estão cheios de falhas como memory leaks, etc.


Afarias ,aonde vc ´viu´ memory Leaks nos códigos ???


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

Na minha modesta opnião, não deve ser usado de jeito nenhum. Além do problema conceitual, os códigos exemplo estão cheios de falhas como memory leaks, etc.


Afarias ,aonde vc ´viu´ memory Leaks nos códigos ???


GOSTEI 0
Knight_of_wine

Knight_of_wine

07/09/2009

Realmente é muito melhor usar Singleton.

Inclusive utilizo uma classe de conexão Singleton muito boa que um amigo criou, assim posso usar minha conexão apenas quando necessito dela.

Isso aumentou a performance de um de meus sistemas em 45¬, algo incrível.

Achei muito massa a iniciativa de discutir um tópico da revista aqui.


GOSTEI 0
Afarias

Afarias

07/09/2009

manter mts objetos enquanto a aplicação está sendo executada pode ser mt caro quando não se tem a real necessidade disso. ... Este é apenas um dos muitos padrões utilizados hj no mercado, existem mts outros, quem não conhece seria uma boa pesquisar e ler um pouco sobre Padrões de Projetos.


Rocha disse tudo.


[quote:bfe68019b8=´Marco Salles´]
Afarias ,aonde vc ´viu´ memory Leaks nos códigos ???
[/quote:bfe68019b8]


1) Nas listagem 3 é criado um construtor para a classe que cria um objeto TStringList que NUNCA é liberado da memória pq não é criado um Destructor que teria esse papel. No texto inclusive é afirmado que o destructor não é necessário!! MAS É!

A não ser que vc utilize interfaces (ref-counted) ou um memory manager habilitado com um garbage collector os objetos criados não são destruídos automaticamente.

2) Nas listagem 5, exemplo com DM, ainda pior... na seção finalization o DataModule NÃO é destruído, apenas ´apontado´ para NIL!

finalization
DMTeste := nil;

Neste caso o ponteiro aponta para nil e a memória que era usada pelo objeto continua sendo utilizada... No texto é alegado que todos os DataModules de um projeto são destruidos ao com o témino da aplicação. Mas está incorreto...

São destruidos automaticamente apenas DataModules (assim como os Forms) criados tendo o objeto Application (ou outro qualquer que seja destruído em algum momento) como OWNER. Sendo que no código o Datamodule em questão NÃO tem um Owner.

DMTeste := TDMTeste.Create(nil);


Achei muito massa a iniciativa de discutir um tópico da revista aqui.


Rsss.. Não achei outro espaço para isso... Achei q era aqui mesmo :wink:


T+


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

[quote:0c834bbb29]Marco Salles escreveu: Afarias ,aonde vc ´viu´ memory Leaks nos códigos ???


1) Nas listagem 3 é criado um construtor para a classe que cria um objeto TStringList que NUNCA é liberado da memória pq não é criado um Destructor que teria esse papel. No texto inclusive é afirmado que o destructor não é necessário!! MAS É!

A não ser que vc utilize interfaces (ref-counted) ou um memory manager habilitado com um garbage collector os objetos criados não são destruídos automaticamente.

2) Nas listagem 5, exemplo com DM, ainda pior... na seção finalization o DataModule NÃO é destruído, apenas ´apontado´ para NIL!

finalization
DMTeste := nil;

Neste caso o ponteiro aponta para nil e a memória que era usada pelo objeto continua sendo utilizada... No texto é alegado que todos os DataModules de um projeto são destruidos ao com o témino da aplicação. Mas está incorreto... [/quote:0c834bbb29]

Afarias , ja tinha percebido uma das falhas e tinha ate reportado o erro em um
email em particular para o autores e um deles gentilmente me respondeu
Como Resposta Obtive que a partir do DataModule foi INVENÇÃO do Pessoal
da Revista ..( Que estã precisando Aprender Delphi )

Agora gostaria de ser solidário aos Autores e isto não encaro como falta .
Errar todos nos erramos . Cometemos Erros e deslizes . Nos aprendemos muito
mais com os erros do que com os Acertos .

O que não podemos aqui em hipotese nenhuma é tomar este Artigo como
o Vilão da História . Vários são os Artigos que podemos considerar como
ruims e ate hj não tomou proporções como a que este esta tomando.
Gostaria de respeitar os autores , e se escrerem outro certamente eu os
lerei , mesmo que seja para critica-los ou não.

A Culpa no meu entender é a falta de um Intercambio mais eficiente entre a Revista e O Forum .


GOSTEI 0
Afarias

Afarias

07/09/2009

Como Resposta Obtive que a partir do DataModule foi INVENÇÃO do Pessoal da Revista ..( Que estã precisando Aprender Delphi ) ...


Veja, esta é uma revista TÉCNICA ao meu ver, e revistas técnicas (e PAGAS) devem apresentar matérias técnicas CORRETAMENTE ou não tem sentido.

Claro q falhas existem, mas tanto autores quanto principalmente os editores técnicos da revista deveriam estar mais atentos ou fica a impressão *no mínimo* de falta de atenção com o leitor.


Mas, voltando...

Meu objetivo com este tópico nem foi criticar -- isto eu fiz em e-mail enviado a REVISTA (não aos autores) q nunca foi respondido. Nem citei autores ou editores...

Meu meu tópico original apenas apresenta uma técnica em alternativa ao que fora colocado na matéria em questão -- na esperança que iniciantes desavisados fiquem atentos.


T+


GOSTEI 0
Weber

Weber

07/09/2009

Não quero defender nem criticar ninguém, um dos autores é um colaborador meu e posso dizer que foi meu aprendiz, eu apresentei o Delphi para ele.
O artigo ´Objetos Auto-instanciáveis´ veio a existir a partir de uma discussão que tivemos sobre classes que criei para facilitar o trabalho da equipe de desenvolvimento, entre estas classes por exemplo tenho uma que chamo de TDBUpdate, os métodos da classe podem ser chamados a qualquer momento de qualquer lugar do sistema sem se preocupar se ela foi instanciada ou não.

Ao meu ver foi uma infelicidade o exemplo aplicado no artigo e não o artigo como um todo.
Vejo tudo como afarias já colocou, a classe deve ser instanciada quando existir realmente e necessidade e não no Initialization, no meu ponto de vista usando o Initialization não houve “auto-instancia”.

Veja abaixo parte de um código com “auto-instancia”
{ TDBUpdate }

procedure TDBUpdate.CheckCreate;
begin
  if not Assigned(DBUpdate) then
    DBUpdate := TDBUpdate.Create(nil);
end;

procedure TDBUpdate.TableCreate(Table: ShortString; Fields: array of ShortString);
begin
  CheckCreate;
  ...
end;


A conversa pode ir muito mais além, um colega meu certificado em java uma vez me disse que eu era louco que um código deste jamais poderia existir.


GOSTEI 0
Afarias

Afarias

07/09/2009

um colega meu certificado em java uma vez me disse que eu era louco que um código deste jamais poderia existir.


rssss... estou com esse seu colega :wink:



T+


GOSTEI 0
Knight_of_wine

Knight_of_wine

07/09/2009

Ao meu ver temos sim que discutir e criticar o artigo, até por que quando eu erro o que mais gosto de ouvir é críticas construtivas e alternativas mais atraentes como essas que encontrei aqui.

Ninguém é dono da verdade, mas podemos sim contribuir para que o pessoal aprimore os artigos e melhorem cada vez mais o conteúdo que pagamos pra ter.


GOSTEI 0
Afarias

Afarias

07/09/2009

Ao meu ver temos sim que discutir e criticar o artigo, até por que quando eu erro o que mais gosto de ouvir é críticas construtivas e alternativas mais atraentes como essas que encontrei aqui. Ninguém é dono da verdade, mas podemos sim contribuir para que o pessoal aprimore os artigos e melhorem cada vez mais o conteúdo que pagamos pra ter.



Na minha opinião, não poderia ter dito melhor.


T+


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

Na verdade o Singleton é muito usado, por exemplo, quando precisamos criar uma classe que pode ter apenas uma única instancia. Então, mesmo que tenhamos várias variáveis dessa classe todas elas apontam para a mesma instancia.

Usa-se muito singleton na aplicação de abstract factory. Ou seja, quando temos uma fábrica de qualquer outro tipo de classe, a fabrica em si so pode ter uma instancia.

A abordagem do afarias é muito boa, eu mesmo já usei muito. Já usei com function, com class function e com um misto dos dois, como o AFarias fez, s sempre colocando uma variavel estatica na seção implementation, para que ela não seja publica global. Ainda tenho o costume de iniciar o nome da variavel com ´__´ para não ter perigo de mecher nela sem querer.

Mas esse tipo de abordagem tem um defeitinho: se o programador desavisado usar o constructor create você acaba tendo duas instancias dessa classe e ela não é mais um singleton. Alem disso o programador desavisado pode esquecer de destruir a instancia dele causando um memory leak, ou pior, ele pode chamar o destroy do objeto singleton, a partir da função, e destruir a unica instancia da aplicação inteira, sem atribuir nil a variavel, causando um monte de acess violations.

Eu conheço umas duas outras maneiras de criar um singleton seguro no Delphi, inclusive thread-safe. Não são dicas de minha autoria, encontrei em sites e blogs de autores bem melhores do que eu, em inglês. Só dei uma ajeitada e uma comentada em português no código pra ficar mais didático.

Não é um código difícil de entender, mas é daqueles que mostram a criatividade do cara que fez, porque você bate o olho e diz: ´Porque eu não pensei nisso antes???´

Assim que eu conseguir acessar o computador da minha casa eu posto os códigos aqui.

Com relação ao artigo, estou com ele aqui mas ainda não li. Seria interessante dar um feedback ao autor ou à edição no próprio site da dev media.

Acredito que com toda essa polêmica com certeza será lançada numa edição futura ou mesmo no site uma errata ou coisa do gênero.

Pessoal, um apelo: muito cuidado com os memory leaks. Memory Leaks fazem as pessoas mudar de C++ ou Delphi para ambientes gerenciados e interpretados com garbage collector, como Java, C#, ou python, simplesmente porque chega uma hora que não conseguem entender onde está o leak.


GOSTEI 0
Afarias

Afarias

07/09/2009

Mas esse tipo de abordagem tem um defeitinho: se o programador desavisado usar o constructor create você acaba tendo duas instancias dessa classe e ela não é mais um singleton.


Isso pode ser evitado, se desejado. Só não coloquei no exemplo pra não ´poluir´. Ex:

implementation

var
  fInstanciaMeuObjeto: TMeuObjeto = nil;
  fPermiteInstanciar: Boolean = False;

{...}

class function TMeuObjeto.Instance: TMeuObjeto;
begin
  if fInstanciaMeuObjeto=nil then
  begin
    fPermiteInstanciar := True;
    try
      fInstanciaMeuObjeto := TMeuObjeto.Create;
    finally
      fPermiteInstanciar := False;
    end;
  end;
  Result := fInstanciaMeuObjeto;
end;

constructor TMeuObjeto.Create; 
begin 
  inherited Create; 
  fLista := TStringList.Create; 
  fNome := ´´; 
  if not fPermiteInstanciar then
    raise Exception.Create(´não é possível criar este objeto´);
end; 



Alem disso o programador desavisado pode esquecer de destruir a instancia dele causando um memory leak


A instância do Singleton?? Não há esse perigo pq sempre é destruída pelo FINALIZATION


ou pior, ele pode chamar o destroy do objeto singleton, a partir da função, e destruir a unica instancia da aplicação inteira, sem atribuir nil a variavel, causando um monte de acess violations.



Rapaz... dar um jeito de avisar esse desavisado seria a solução mais fácil.. rsss :wink:

Bom, mas isso tb pode ser evitado de diversas formas (numa classe mais trabalhada). Um exemplo seria modificando o Destructor incluindo depois do ´inherited´ a linha

InstanciaMeuObjeto := nil;

dai, vc poderia fazer:

MeuObjeto.Free;
MeuObjeto.Free;
MeuObjeto.Free;
MeuObjeto.Nome := ´Teste 1´;
MeuObjeto.Free;
MeuObjeto.Free;
MeuObjeto.Nome := ´Teste 2´;


E nunca haver erros.

Uma vez q a implementação do singleton utiliza um método/função de entrada, vc pode ´incrementar´ como desejar.


Com relação ao artigo, estou com ele aqui mas ainda não li. Seria interessante dar um feedback ao autor ou à edição no próprio site da dev media.


Com certeza. A primeira coisa q fiz.


Acredito que com toda essa polêmica com certeza será lançada numa edição futura ou mesmo no site uma errata ou coisa do gênero.


Polêmica? Q polêmica?? :lol:


T+


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

ficou legal dessa maneira ^^



quando eu disse

Alem disso o programador desavisado pode esquecer de destruir a instancia dele causando um memory leak


me referia a uma instancia que ele mesmo criasse.


Agora liga só nesse singleton:

A classe Tobject tem uma class function chamada NewInstance e uma procedure chamada FreeInstance. Essas duas são as responsáveis por criar ou destruir um objeto DE VERDADE. Por exemplo, sempre o constructor create chama new instance internamente, e o destructor destroy chama freeinstance.

Pode criar um override dessas duas com um showmessage que você vai ver.

Então.... você pode criar um override dessas duas para controlar a criação e destruição do seu singleton. E não preciasa usar uma function ou método especial para isso, você pode usar o constructor create mesmo, na maior cara de pau. O Create, ao invez de te dar uma nova instancia, vai dar a padrão que já estava criada.

A mesma coisa se vc ficar chamando free ou destroy, ele não vai destruir de verdade a não ser que você chame PrepararParaDestruir antes.

Assim você não precisa disparar uma exception se alguém criar ou destruir um singleton. Isso é bom para equipes muito grandes ou venda de bibliotecas pre compiladas.

Esse tipo de singleton não pode ter descendentes, a não ser que varias coisas sejam reescritas, porque senão o descendente será instanciado na variavel publica do ancestral, e o destroy não vai destruir e desalocar objetos especificos do descenente, só do ancestral. (a não ser que você refaça boa parte do descendente)

Agora, sebe essas duas variaveis publicas que você criou? uma para conter ainstancia e outra para dizer se pode destruir? Eu tambem uso assim, mas num delphi 2007 ou posterior que você pode criar variaveis de classe e propriedades de classe fica muito mais show de bola, você não usa variaveis na implementation e ainda pode gerar descendentes do seu singleton que vão funcionar uma belezinha.

Eu ainda ponho o método para preparar para destruir como privado e estático, uma private class procedure. Assim eu só posso chamar ela da propria unit, apenas na seção finalization. Assim eu não inicializo minha aplicação com o singleton criado. Crio ele ao longo do uso da aplicação apenas se precisar e mato sua unica instancia quando finalizo a aplicação.

{
  essa unit tem uma classe que implementa o padrão singleton, ou seja, apenas
  uma instancia desta pode existir.

  você não pode dar free nesse objeto, mas ele é liberado da memoria
  automaticamente atraves da seção finalization da unit, executando o
  metodo privado estatico (a unica utilidade que eu já vi para metodo privado
  estatico)      class procedure PrepararParaLiberar; Depois disso o objeto pode
  ser destruido normalmente

  Essa classe não pode ter descendentes. Se tiver, a variavel global que
  guarda a instancia do singleton conterá apenas uma instancia, ou da
  classe base ou da classe especializada.


  Ao ser liberada da memoria o metodo destroy
  da classe herdada não conseguirá liberar objetos
  criados e usados somente por esta classe
}

unit uSingleton;

interface

uses Dialogs, Classes;

type

  TMySingleton = class(TObject)
  private
    FHello: TstringList;
    //se executar isso o objeto pode ser destruido
    class procedure PrepararParaLiberar;
    //para criar ou destruir os componentes do objeto
    procedure InicializarObjeto;
    procedure FinalizarObjeto;
  public
    procedure SetHello(vHello: string);
    procedure SayHello; virtual;

    //esses caras misticos abaixo que realmente criam, alocam memoria, destroem e desalocam memoria por tráz dos constructor e destructor que conhecemos
    class function NewInstance: TObject; override;
    procedure FreeInstance; override;

    constructor Create;
    destructor Destroy; override;

    class function InstanciaPadrao: TMySingleton;

  end;

implementation

var
  _MySingletonInstance: TMySingleton = nil;
  _PreparadoParaLiberar: Boolean = False;

{ TMySingleton }


procedure TMySingleton.SayHello;
begin
  //um metodo bobo pra testar
  ShowMessage(FHello.Text);
end;

procedure TMySingleton.SetHello(vHello: string);
begin
  //um outro metodo bobo pra setar a mensagem
  FHello.Text := vHello;
end;




constructor TMySingleton.Create;
begin
  //antes de tudo, antes mesmo do inherites, newinstance já é chamado por padrão
  inherited; //faz o que for preciso de seu ancestral, eu tenho certeza aqui que o NewInstance está sendo executado
  InicializarObjeto; //inicializo o que precisa
end;

destructor TMySingleton.Destroy;
begin
  FinalizarObjeto;  //destruo as partes ou objetos criados pela minha classe, como stringlists
  inherited;    //a destruição normal do objeto, depois disso freeinstance é chamado normalmente
end;



class function TMySingleton.InstanciaPadrao: TMySingleton;
begin
  //isso é apenas um atalho em uma class function
  Result := _MySingletonInstance;
end;





procedure TMySingleton.FreeInstance;
begin

  //no destructor não vai acontecer nada se _PreparadoParaLiberar for false, e eu não preciso disparar uma excessão

  //  agora se _PreparadoParaLiberar for true
  //eu faço o que um FreeInstance sempre deveria fazer, uso o inherited,
  if _PreparadoParaLiberar then
  begin
    inherited;
    //bloqueio a liberação  novamente
    _PreparadoParaLiberar := False;
    //atribuo nil
    _MySingletonInstance := nil;
  end;

  //agora se precisar pode criar de novo

end;

class function TMySingleton.NewInstance: TObject;
begin

  //se não está criada cria usando o inherited NewInstance da classe ancestral, TObject e atribui fazendo typecasting
  if _MySingletonInstance = nil then
  begin
    _MySingletonInstance := (inherited NewInstance as TMySingleton);
  end;

  //e retorna a mesma
  result := _MySingletonInstance;
end;

class procedure TMySingleton.PrepararParaLiberar;
begin
  //esse método só faz isso
  _PreparadoParaLiberar := True;
end;

procedure TMySingleton.FinalizarObjeto;
begin
  //aqui você poe somente as coisas que devem acontecer da destruição verdadeira do objeto
  if _PreparadoParaLiberar then
  begin
    FHello.Free;
  end;
end;

procedure TMySingleton.InicializarObjeto;
begin
  //aqui você poe tudo o que precisa que aconteça depois do create
  //lembrando que se o NewInstance já retornar o objeto criado, então
  //Self.FHello vai ser o Fhello dessa instancia, e vai ser <> de nil
  if (FHello = nil) then
  begin
    FHello := TStringList.Create;
  end;
end;



initialization
  //inicializo minhas variáveis publicas, porque vou mecher nelas posteriormente
  _MySingletonInstance := nil;
  _PreparadoParaLiberar := False;



finalization
  if Assigned(_MySingletonInstance) or (_MySingletonInstance <> nil) then
  try
    try
      TMySingleton.PrepararParaLiberar;
      _MySingletonInstance.Free;
    except
      //tratamento de excesão, se precisar
    end;
  finally
    _MySingletonInstance := nil;
  end;

end.

{
  faça o teste derradeiro: coloque um button na form e:

procedure TForm1.Button9Click(Sender: TObject);
var fmst: TMySingleton;
begin

  fmst := TMySingleton.Create;
  fmst.SetHello(´teste1´);
  fmst.SayHello;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;
  fmst := TMySingleton.Create;

  fmst.SetHello(´teste2´);
  fmst.SayHello;

  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Free;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;
  fmst.Destroy;

  fmst.SetHello(´teste3´);
  fmst.SayHello;

end;


}



GOSTEI 0
Afarias

Afarias

07/09/2009

Sim, usando NewInstance/FreeInstance é muito válido, ótima opção.


Só um detalhe falho no código apresentado é que o utilizador da classe obrigatoriamente deve chamar o construtor antes de puder usá-la (se antes disso tentar chamar ´InstanciaPadrao´ ocorrerá violação de memória)

Como, na minha opinião, não deve haver necessidade de chamar o construtor, deve-se rever o código de ´InstanciaPadrao´


T+


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

Só um detalhe falho no código apresentado é que o utilizador da classe obrigatoriamente deve chamar o construtor antes de puder usá-la (se antes disso tentar chamar ´InstanciaPadrao´ ocorrerá violação de memória)


Como, na minha opinião, não deve haver necessidade de chamar o construtor, deve-se rever o código de ´InstanciaPadrao´


é mais ai ´acho´ que pode usar a ´sua estrategia´

Note que foi criada uma FUNÇÃO como ponto de acesso global a instância do objeto e não uma variável.


type
  TMySingleton = class(TObject)
  private
   bla bla ...
  public
    bla ... bla;;
  // class function InstanciaPadrao: TMySingleton;  ********* Aqui 
  end;

function InstanciaPadrao: TMySingleton;


E alterando um Pouco o método ... chamando o Create...

class function TMySingleton.NewInstance: TObject;
begin
 //se não está criada cria usando o inherited NewInstance da classe ancestral, TObject e atribui fazendo typecasting
  if _MySingletonInstance = nil then
  begin
    _MySingletonInstance := (inherited NewInstance as TMySingleton).Create;
  end;

  //e retorna a mesma
  result := _MySingletonInstance;
end;

Acho que resolve ...


GOSTEI 0
Afarias

Afarias

07/09/2009

Verdade Marcos, por exemplo:


class function TMySingleton.InstanciaPadrao: TMySingleton;
begin
Result := TMySingleton.Create;
end;


É uma forma de resolver esse ´problema´, visto que Create sempre retorna a mesma instância

=)


T+


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

Pois é, como eu disse, coloquei esse class method InstanciaPadrao apenas como um atalho e nem me dei conta do erro.

O objetivo era que se usasse o Create mesmo, o Create ia criar a primeira instancia quando chamado a primeira vez, mas ia ser o metodo que chamasse a instancia padrão sempre, ou seja, poderia chamar TMySingleton.Create().SayHello, por exemplo. só que ....

... então o ´InstanciaPadrao ´ era desnecessário.... mas eu introduzi um bug quando inseri ele....

Valew pela dica.

Dá pra resolver assim:

class function TMySingleton.InstanciaPadrao: TMySingleton; 
begin 
  //isso é apenas um atalho em uma class function 
  Result := TMySingleton.Create; 
end; 


Mas, como sabemos, Create é um método, que chama internamente varios outros métodos, empilhando os endereços de retorno das funções no stack e causando um pequeníssimo overhead.


Seria elegante criar um misto com a função tradicional do Afarias assim:

class function TMySingleton.InstanciaPadrao: TMySingleton; 
begin 
  //isso é apenas um atalho em uma class function 

  if _MySingletonInstance = nil then
    _MySingletonInstance := TMySingleton.Create;

  Result := _MySingletonInstance ;

end; 


Acho que não é uma repetição de concreta de código, na cara lavada, é meio que uma repetição abstrata, mais um artificio de documentação, porque ele é muito parecido com o proprio método NewInstance em sua estrutura, mas encapsula e dá mais um nivel de indireção na chamada do método. Ele torna claro qual é o real objetivo desse método, que não é criar varias vezes ou criar sempre, mas criar apenas quando não está criado.

Diminui um pouco o overhead do stack porque quando já está criado retorna a instancia direto ao invés de chamar o create e empilhar mais coisas no stack.

Só um loop muito grande agora pra dizer se ganhamos um minimo de performance com isso.


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

[quote:782ad5990b=´Marco Salles´]E alterando um Pouco o método ... chamando o Create...

Código:
class function TMySingleton.NewInstance: TObject;
begin
//se não está criada cria usando o inherited NewInstance da classe ancestral, TObject e atribui fazendo typecasting
if _MySingletonInstance = nil then
begin
_MySingletonInstance := (inherited NewInstance as TMySingleton).Create;
end;

//e retorna a mesma
result := _MySingletonInstance;
end;

Acho que resolve .....[/quote:782ad5990b]

Marco, não faz isso porque o NewInstance é ´o verdadeiro create por trás do create´.

Se você fizer isso, veja bem, o newinstance já te traz uma instancia do objeto. Aí você vai acabar chamando o constructor create a partir de uma instancia...

Como Create nesse caso tá trazendo a mesma instancia padrão, funciona, mas você chama create desnecessariamente e fica estranho.

Se não fosse um singleton você acabaria criando duas instancias, uma delas sem referencias, sem que você possa destruir, causando um memory leak.

E se você esquecer o inherited, causa um loop infinito recursivo.


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

Como Create nesse caso tá trazendo a mesma instancia padrão, funciona, mas você chama create desnecessariamente e fica estranho. [quote:b3cf6c9277]_MySingletonInstance := (inherited NewInstance as TMySingleton).Create;


Se não fosse um singleton você acabaria criando duas instancias, uma delas sem referencias, sem que você possa destruir, causando um memory leak. [/quote:b3cf6c9277]

Minha resposta foi de prontidão , conhecendo estes ´riscos´ . Apesar de
estranho , apliquei ao seu ´Modelo´ , levando em conta a sugestão de
Afarias , so que simplesmente tb deve resolver.

function InstanciaPadrao: TMySingleton;
begin
 if _MySingletonInstance = nil then
    _MySingletonInstance := TMySingleton.Create;

  Result := _MySingletonInstance
end;


Mas acredito que suas recomendações tb se aplica neste Modelo.
(por se tratar de um Singleton , etc...

So não entendo porque vc ainda esta usando function InstanciaPadrao
como Método de classe , as chamadas no meu entendimento foge
do modelo proposto do Afarias

TMySingleton.InstanciaPadrao.SetHello(´oi´);  //usando metodo de classe
  InstanciaPadrao.SetHello(´oi´);  //Declarando um Função 



GOSTEI 0
Afarias

Afarias

07/09/2009

|Mas, como sabemos, Create é um método, que chama internamente
|varios outros métodos, empilhando os endereços de retorno das funções
|no stack e causando um pequeníssimo overhead.

Acredito que não Vitor.

Quem trata da parte de memória no Create é o NewInstance (que por sua vez chama o InitInstance). Uma vez que vc re-escreveu o NewInstance para verificar se existe já uma instância não haverá nova alocação de memória ou qualquer ´overhead´ ao chamar o Create várias vezes. (que não seja o do código q está em NewInstance de qualquer forma)


|So não entendo porque vc ainda esta usando function InstanciaPadrao
|como Método de classe , as chamadas no meu entendimento foge
|do modelo proposto do Afarias

Não foge marcos. Vc tanto pode usar um método de classe E/OU uma função. Como vc disse a função deixa mais prático (uma espécie de ´alias´), dai é só criá-la:


function MeuSingleton: TMeuSingleton;
begin
Result := TMeuSingleton.InstanciaPadrao;
end;


Os 2 exemplos de implementação são muito semelhantes, como pequenos detalhes de implementação apenas. Até pq o Singleton é um padrão de projeto muito simples, não tem muito o que inventar.

Eu particularmente prefiro a abordagem q exemplifiquei pq acho mais simples, fácil de ler e implementar.



Alguns comentários (detalhes) ainda sobre o codigo ´finalization´:


if Assigned(_MySingletonInstance) or (_MySingletonInstance <> nil) then 


esse OR não precisa, pois Assigned(Obj) é igual a Obj<>nil


try
  ...
finally 
  _MySingletonInstance := nil; 
end; 


esse [ try... finally Obj := nil ] no finallization tb é desnecessário uma vez q vc nunca mais precisa saber se o objeto é NIL depois disso.


T+


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

So não entendo porque vc ainda esta usando function InstanciaPadrao como Método de classe , as chamadas no meu entendimento foge do modelo proposto do Afarias Código: TMySingleton.InstanciaPadrao.SetHello(´oi´); //usando metodo de classe InstanciaPadrao.SetHello(´oi´); //Declarando um Função


Eu costumo fazer com class method simplesmente por estilo e organização. Eu não tenho uma função global, tenho que achar a classe e fazer classe.metodo. O resto dá no mesmo.

|Mas, como sabemos, Create é um método, que chama internamente |varios outros métodos, empilhando os endereços de retorno das funções |no stack e causando um pequeníssimo overhead. Acredito que não Vitor. Quem trata da parte de memória no Create é o NewInstance (que por sua vez chama o InitInstance). Uma vez que vc re-escreveu o NewInstance para verificar se existe já uma instância não haverá nova alocação de memória ou qualquer ´overhead´ ao chamar o Create várias vezes. (que não seja o do código q está em NewInstance de qualquer forma)



Como eu disse, não estou falando de overhead de alocação de memoria, mas overhead de empilhamento de metodos no stack.

Por exemplo, digamos que o metodo4 instancia um objeto, alocando memoria. (ou nem faz isso e faz qualquer outra coisa, tanto faz)

Se o metodo1 chamar o metodo2 que por sua vez chamar o metodo3 que chamar o metodo4 eu empilho muito mais endereços de retorno de metodos no stack do que simplesmente chamar o metodo4 direto. Foi isso o que eu quis dizer. Porque InstanciaPadrao chama create, que chama NewInstance, que chama InitInstance.... e assim vai. Podemos economizar essa chamada verificando a variavel.

Alguns comentários (detalhes) ainda sobre o codigo ´finalization´: Código: if Assigned(_MySingletonInstance) or (_MySingletonInstance <> nil) then


Isso é vicio hauahauahuahau, não tem jeito, eu não aprendo

Código: try ... finally _MySingletonInstance := nil; end; esse [ try... finally Obj := nil ] no finallization tb é desnecessário uma vez q vc nunca mais precisa saber se o objeto é NIL depois disso.


Também é outro vicio... mas aqui por questões de clareza para mim mesmo.

E acredito que se for uma bpl carregada dinamicamente precisamos fazer isso, ou estou enganado?


GOSTEI 0
Afarias

Afarias

07/09/2009

[quote:150d02d13a=´vitor^_^´]E acredito que se for uma bpl carregada dinamicamente precisamos fazer isso, ou estou enganado?[/quote:150d02d13a]

Tb não é necessário


T+


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

Blz ,estamos encaminhando para o MMC .
Mas qnd me referi a ´foge´ , não foi mereferindo ao Modelo propriamemte dito.
mas sim a ´Chamada´

[quote:e84c108de4]|So não entendo porque vc ainda esta usando function InstanciaPadrao |como Método de classe , as chamadas no meu entendimento ´foge´ |do modelo proposto do Afarias


Não foge marcos. Vc tanto pode usar um método de classe E/OU uma função. [b:e84c108de4]Como vc disse a função deixa mais prático (uma espécie de ´alias´), [/b:e84c108de4]dai é só criá-la:
[/quote:e84c108de4]

é isto que estava me referindo.... Deixar mais prático


GOSTEI 0
Fabriciocolombo

Fabriciocolombo

07/09/2009

Eu utilizo uma abordagem um pouco diferente. Vi este tipo de implementação no framework INFRA de autoria de Marcos Barreto (mrbar2000), não sei se é de autoria dele, mais achei muito simples.

A principal diferença é que utiliza uma Interface como forma de acesso ao Singleton, eliminando a necessidade de controle de Criação e Destruição da Classe. Dessa forma é impossivel um desenvolvedor desavisado criar uma nova instancia ou destruir a instância.

unit uSingleton;

interface

uses
  SyncObjs, Dialogs;

type
{*-----------------------------------------------------------------------------
  Interface que define os métodos do Singleton
-------------------------------------------------------------------------------}
  ISingleton = interface
  [´{93E92DC7-BF57-4BD5-9ACF-B69E75EC37D0}´]
    procedure FacaAlgo;
  end;

{*-----------------------------------------------------------------------------
  Retorna a instância de um objeto que implementa a interface ISingleton.
-------------------------------------------------------------------------------}
  function Singleton: ISingleton;

implementation

var
  _Singleton: ISingleton = nil;

type
{*-----------------------------------------------------------------------------
  Classe interna que implementa a interface ISingleton.
-------------------------------------------------------------------------------}
  TSingleton = class(TInterfacedObject, ISingleton)
  private
  public
    procedure FacaAlgo;
  end;

  function Singleton: ISingleton;
  begin
    if not Assigned(_Singleton) then
    //Aqui poderia ter um Critical Section para ficar thread-safe
      _Singleton := TSingleton.Create as ISingleton;
      
    Result := _Singleton; 
  end;
  
{ TSingleton }

procedure TSingleton.FacaAlgo;
begin
  ShowMessage(´Estou fazendo algo...´); 
end;

end.



GOSTEI 0
Afarias

Afarias

07/09/2009

A principal diferença é que utiliza uma Interface como forma de acesso ao Singleton, eliminando a necessidade de controle de Criação e Destruição da Classe. Dessa forma é impossivel um desenvolvedor desavisado criar uma nova instancia ou destruir a instância.


Esta implementação é muito interessante... (apesar de ter que definir a interface a implementar a classe). Mas ainda me surgem 2 pequenas observações:

1) O desenvolvedor ´desavisado´ deve entender de interfaces, pq não é difícil para um ´desavisado´ bagunçar o sistema de ´reference counting´ que as interfaces usam como ´garbage collect´ no Delphi e ai ter em mãos erros e memory leaks que nem sabe de onde vem.


2) Com esta abordagem o desenvolvedor não pode implementar um Form ou DataModule como Singleton (já que a definição destes não pode ser feita em ´implementation´)


T+


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

Essa abordagem nova é muito legal. Mas tirando o fato de a classe singleton ser definida debaixo de implementation, de resto essa abordagem é idêntica à primeira abordagem que vimos nesta discussão, do Afarias.

A maior diferença está no uso da interface. A variavel local _Singleton e a função

  function Singleton: ISingleton; 
  begin 
    if not Assigned(_Singleton) then 
    //Aqui poderia ter um Critical Section para ficar thread-safe 
      _Singleton := TSingleton.Create as ISingleton; 
      
    Result := _Singleton; 
  end; 


são do tipo ISingleton.

Podemos fazer uma junção das duas abordagens.

E assim não precisa se preocupar com a destruição do objeto.


Existem 1000 maneiras de preparar singleton!


GOSTEI 0
Fabriciocolombo

Fabriciocolombo

07/09/2009

Exatamente, vai da necessidade de cada um. Para atender a minha necessidade não tem problema a classe estar no implementation e o metodo ser declarado em uma interface, pois meus singleton normalmente são factories ou classes simples.

Também é possivel fazer apenas com a classe, como exemplos postados, já utilizei essa abordagem tbm, mais precisa fazer o controle nos metodos NewInstance e FreeInstance. É um pouco mais trabalhoso, mais também funciona perfeitamente.


GOSTEI 0
.lg.

.lg.

07/09/2009

Exatamente, vai da necessidade de cada um. Para atender a minha necessidade não tem problema a classe estar no implementation e o metodo ser declarado em uma interface, pois meus singleton normalmente são factories ou classes simples.

Precisei dar uma lida e estudar um pouco para me inteirar e poder argumentar.

Mas tenho uma dúvida. que se daria para ser feito. Fiquei imaginando uma maneira de faze-lo. Não sei se estou pensando de forma complicada ou se poderia ser mais simples.

Eu poderia implementar uma Factory sobre um Singleton!?
Pensei num jogo de tetris, only um bloco representaria o singleton e eu os construísse nós blocos montados, pois pensei que todos os blocos vem da mesma estrutura.
(Gostaria de poder entender se meu pensar está correto ou se eu estou fazendo confusão quanto a sua utilização :? )


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

Geralmente, quando temos factory methods ou abstract factories a classe fábrica, que irá criar as outras é um singleton. Não tem sentido ter várias fábricas.

Mas obviamente a sua fábrica pode criar objetos diferentes da mesma linhagem ou que implementem a mesma interface dependendo de seu estado ou dos valores de suas propriedades. Mas isso é uma excessão.

Quando uma fábrica precisa criar objetos de tipos diferentes você usa um abstract factory ou até uma fábrica de fábricas.

Por exemplo, eu poderia ter uma fábrica que criasse clientes e fornecedores, já que ambos seriam do tipo Pessoa. Porem usasse metodos diferentes para criar Cliente e Fornecedor, ou usasse o mesmo metodo mas criasse objetos diferentes de acordo com o valor da propriedade ´Tipo´, que poderia ser cliente ou fornecedor.

Daí eu poderia ter duas instancias dessa fábrica, uma para criar cada tipo de objeto. Mas como eu já disse o mais comum é que se use duas fábricas diferentes descendentes da mesma fábrica abstrata e que ambas sejam singletons. Assim você evita que a fábrica de clientes seja obrigada a conhecer a unit de fornecedores.

Como você está fazendo um jogo de Tetris e cada ´peça´ do tetris é formada por 4 blocos, mudando apenas a posição dos mesmos você pode usar Um singleton de fábrica de blocos para criar os blocos e um builder para montar as peças. Randomicamente o builder sempre criaria 4 blocos usando a factory e os disporia com as faces coladas uns nos outros, formando as peças de Tetris T L Z | [] e assim por diante. O Builder retornaria um objeto formado pelos 4 blocos já conectados e configurados.


GOSTEI 0
.lg.

.lg.

07/09/2009

Não havia pensado no Builder. Mas agora eu entendo. Já que me esclareceu a dúvida posso ter certeza de que estou no caminho certo. Meu único problema agora seria um metodo que verificasse a colisão de multiplos objetos. Consigo pensar em algo. Mas não vamos fugir o assunto do tópico.
Obrigado Vitor.


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

...Meu único problema agora seria um metodo que verificasse a colisão de multiplos objetos...


Eu sempre achei essa parte a mais difícil :wink:

Vamos abrir um tópico só pra isso? Tenho certeza que terão muitas contribuições, Você pode postar a maneira como você fez.


GOSTEI 0
.lg.

.lg.

07/09/2009

[quote:150d02d13a=´vitor^_^´]
...Meu único problema agora seria um metodo que verificasse a colisão de multiplos objetos...


Eu sempre achei essa parte a mais difícil :wink:

Vamos abrir um tópico só pra isso? Tenho certeza que terão muitas contribuições, Você pode postar a maneira como você fez.[/quote:150d02d13a]
Se quiser toma a iniciativa. Eu ainda não elaborei um metodo que possa fazer isso com multiplos objetos. Porém eu tenho o código que verifica a colisão entre 2 objetos. Até aí construir um ´Space Invaders´ seria facil (meu primeiro jogo).

Estou vendo como vou fazer para o metodo varrer a lista dos objetos gerados. Isto é fazer a factory gerar a lista de objetos já criados. Outros fatores, seria fazer a lógica para o metodo entender quando dois objetos formam uma parede, fazer anular os pontos onde os 2 objetos se encontram. (já elaborei teoricamente).

Se quiser tomar a iniciativa, eu discuto o tópico. A princípio estou com estudos focados em objetos 2D.

Abraços.


GOSTEI 0
Marcosrocha

Marcosrocha

07/09/2009

Agradeço a todos pelo feedback. Como este foi minha primeira publicação, era de se esperar que ocorresse um pequeno erro como foi o exemplo final do artigo. Realmente o objeto é criado na utilização da unit como foi dito primeiramente e o método deve ser usado com critério a fim de evitar consumo demasiado de memória e possíveis memory leaks.
Se possível trarei mais artigos em breve. Qualquer coisa estou sempre no fórum à disposição. Abraços.

PS.: Realmente o Weber é doido.


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

Não se preocupa com isso, cara. Herrar é umano. O que seria de nós programadores se não fossem nossos proprios bugs?

Num outro artigo que você falar sobre o mesmo assunto, mostra uma outra aplicação ou maneira de implementar, vai mais afundo na coisa que você se ´redime´.

não é o primeiro artigo que gerou ´polêmica´. Eu acho tudo isso bastante saudável e construtivo. Conheci esse forum através da revista e o encaro como uma extensão da mesma, onde todos podemos ser editores.

Acho que quando sair meu primeiro artigo eu vou morrer de medo :oops: :shock:

vou ficar um mês sem sair de casa... hauahuaha


GOSTEI 0
Marco Salles

Marco Salles

07/09/2009

MarcosRocha que ninguem duvide de sua capacidade amigo.
Vc é um parceirão e sempre contrinbui de forma limpa, cortes , amigavel,
para este forum. Não estamos aqui a julgar o seu trabalho , mas sim
aperfeicoar nosso pequeno conhecimento

ps: fui eu quem lhe enviou o email
salhamoda = Marco Salles


GOSTEI 0
Marcosrocha

Marcosrocha

07/09/2009

Então, críticas construtivas sempre são aproveitadas. Podem contar comigo sempre, pois enquanto eu tiver raciocínio lógico vou estar aqui com vocês.
Com relação ao que o .lg. disse, eu estou tentando desenvolver uma engine de física em Delphi para controlar reações de ângulo de colisões entre esferas de mesmo tamanho, desprezando forças externas. Mas estou preso à fisica, tendo em vista que eu não tive faculdade disto em Sistemas de Informação. Caso haja um tópico específico para isto, estarei feliz em participar.

Abraços


GOSTEI 0
Vitor Rubio

Vitor Rubio

07/09/2009

  Fiz uma nova versão desse nosso singleton, citei que foi baseado nessa nossa discussão que chegamos mais ou menos em um "acordo" :)

A versão nova do singleton pode ser vista aqui:

http://blog.vitorrubio.com.br/2011/02/existem-1001-maneiras-de-preparar.html
GOSTEI 0
José

José

07/09/2009

Este tópico esta sendo fechado por inatividade. Se necessário, sinalizar para que seja reaberto ou abrir um novo.
GOSTEI 0
POSTAR