Duvida sobre POO

Delphi

21/09/2006

Salve galera,

bom tenho a seguinte duvida:

se dentro e uma classe tenho alguns métodos que criam objetos: TADOConnection, TADOQuery etc.

quando eu destruir( destructor ) essa classe ( TClasse.Free; ) os objetos tambem serao destruidos ????


Fabiano Góes

Fabiano Góes

Curtidas 0

Respostas

Massuda

Massuda

21/09/2006

[quote:2e74780374=´Fabiano Góes´]quando eu destruir( destructor ) essa classe ( TClasse.Free; ) os objetos tambem serao destruidos ????[/quote:2e74780374]Geralmente não, é responsabilidade de quem criou um objeto destruir o objeto quando ele não for mais necessário.

A exceção é um mecanismo da VCL para classes derivadas de TComponent (geralmente itens visuais) que implementa a destruição automática dos objetos que são possuídos por outro (através da propriedade Owner).


GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

se é que eu entendi bem , sua duvida , acho que nao é aconelhavel , usar os metodo de uma classe para criar objetos de outras classes

O correto é que esses objetos façam parte do atributos desta classes e devam ser instanciados no constructor e destruidos no destructor desta calsse

Tipo isto

Type TminhaClass = class(.... private var objeto1:TObjeto1; objeto2:TObjeto2; etc... public constructor create; desTructor Destroy; outros metodos.... end;


implementation

constructor TminhaClass.Create; begin objeto1:TObjeto1,Create; objeto2:TObjeto2.Create; et.... end;


Destructor TminhaClass; begin objeto1.free; objeto2.free; end



GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

Beleza, entendi !!!!
Valeu Massuda e Marcos Salles !!!!

aproveitando a situação,

qual a diferença:
TClasse.Free <-> FreeAndNil( TClasse ) ?



GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

veja , na minha opinião , ate observei que voce postou , não se existe

TClasse.Free <-> FreeAndNil( TClasse )


metodos são apliclados as objetos de uma classe ...,. existem tb ,metodos de classe , (com é o caso de constructor e descturctor) mas acho que este não é o seu caso

mas vamos supor que voce faça:
var
umObjeto:TMinhaClasse;
begin
UmObjeto:=TminhaClasse.Create;
umObjeto.Free;
ou
FreeandnIL(UmObjeto)

o metodo free não configura o objeto como nil... Dentro do metodo free , conhecemos o endereço da memoria do objeto criado <objeto Instanciado > , mas não conhecemos a posicao da memoria da variavel ( var umObjeto) que esta fazendo referencia ao Objeto.. Portanto o metodo free não pode afetar a variavel e configura-la como nil

Ao chamarmos um procedimento externo como o FreeandNil , ele sabe sobre a referencia (var) ao Objeto e pode atuar sobre esta referencia configurando-a como nil

em outras palavras

FreeandNil(meuObjeto) = MeuObjeto.Free + MeuObjeto:=nil



GOSTEI 0
Massuda

Massuda

21/09/2006

Ambos fazem a mesma coisa

SeuObjeto.Free

* funciona mesmo se SeuObjeto = nil (na verdade, quando SeuObjeto = nil, não faz nada )
* depois de executado, SeuObjeto <> nil e é inválido

FreeAndNil(SeuObjeto)

* falha se SeuObjeto = nil
* depois de executado, SeuObjeto = nil


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

Valeu Massuda e Marco Salles,

obrigado pela atenção !!!!


GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

uma coisa importante que foi colocado Fabiano Góes é que free não configura o Objeto como nil , mas torna o Ponteiro inválido

* depois de executado, SeuObjeto <> nil e é inválido


é um pequeno detalhe , mas acho notável

veja

meuObjeto.Free; if meuObjeto <> nil then meuObjeto.SeuMetodo; **** //o teste sera satisfeito e teremos um erro nesta Linha



GOSTEI 0
Michael

Michael

21/09/2006

[quote:af17744c81=´Marcos Salles´]se é que eu entendi bem , sua duvida , acho que nao é aconelhavel , usar os metodo de uma classe para criar objetos de outras classes.
O correto é que esses objetos façam parte do atributos desta classes e devam ser instanciados no constructor e destruidos no destructor desta calsse [/quote:af17744c81]
Isso depende, [b:af17744c81]Marcos Salles[/b:af17744c81]. Há casos onde a criação de um objeto é custosa e só deve ser feita qdo realmente necessário. É o caso de um acesso a um banco de dados.

Nessas situações, uma best practice é inicializar a variável com nil no construtor da classe, e no método que a utiliza, verificar a sua nulidade e instanciar o objeto de fato. No destrutor, ao chamar Free, não ocorrerá erro mesmo que o ponteiro ainda esteja nulo.

Ambos fazem a mesma coisa

Na verdade, [b:af17744c81]Free [/b:af17744c81]e [b:af17744c81]FreeAndNil [/b:af17744c81]têm funções diferentes. Enquanto [b:af17744c81]Free [/b:af17744c81]verifica a nulidade do objeto e chama o seu destrutor caso a instância seja diferente de nil, [b:af17744c81]FreeAndNil [/b:af17744c81]chama [b:af17744c81]Free [/b:af17744c81]e depois anula o ponteiro da variável do objeto (tecnicamente falando não ocorre nessa ordem, mas o efeito prático é o mesmo).

FreeAndNil(SeuObjeto) * falha se SeuObjeto = nil * depois de executado, SeuObjeto = nil

[b:af17744c81]FreeAndNil [/b:af17744c81]não falha mesmo que o objeto seja nil, pois ele chama [b:af17744c81]Free[/b:af17744c81], que faz o teste de nulidade mencionado anteriormente.


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

[quote:d0d7b4dbcd=´Marco Salles´]uma coisa importante que foi colocado Fabiano Góes é que free não configura o Objeto como nil , mas torna o Ponteiro inválido

* depois de executado, SeuObjeto <> nil e é inválido


é um pequeno detalhe , mas acho notável

veja

meuObjeto.Free; if meuObjeto <> nil then meuObjeto.SeuMetodo; **** //o teste sera satisfeito e teremos um erro nesta Linha
[/quote:d0d7b4dbcd]

Marco Salles,
foi justamente um caso como este que me levou a fazer este post,

depois de usar
 MeuObjeto.Free; 


em outra parte do codigo eu fazia um teste:
if MeuObjeto = nil then //<- aqui o teste era falso
  MeuObjeto.Create;  // se era falso nao entrava  

MeuObjeto.Metodo;   //<- aqui gerava um erro pois o "Free" nao tinha
                    // configurado o o Objeto com nil apenas tornou o 
                    // ponteiro inválido


mais agora ficou claro :D

valeu !!!


GOSTEI 0
Siam

Siam

21/09/2006

Aproveitando o assunto, Free testa se o objeto é nil e se não for executa o Destroy. Se der Free 2 vezes, pode dar erro na segunda vez ?


GOSTEI 0
Michael

Michael

21/09/2006

Aproveitando o assunto, Free testa se o objeto é nil e se não for executa o Destroy. Se der Free 2 vezes, pode dar erro na segunda vez ?

Sim. Podem ocorrer desde um erro de operação de ponteiro inválida ([b:e70dd92ead]Invalid pointer operation[/b:e70dd92ead]) até uma violação de acesso ([b:e70dd92ead]Access violation[/b:e70dd92ead]), pois o método [b:e70dd92ead]Free [/b:e70dd92ead]não pertencerá mais a uma instância válida do objeto.

Entretanto, pode-se chamar [b:e70dd92ead]FreeAndNil [/b:e70dd92ead]inúmeras vezes e estes erros não irão acontecer.

[]´s


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

Aproveitando esse post que é sobre POO, tenho mais uma duvida:

Exemplo:
Tenho uma classe
TPai = class
//que tem o metodo:
Constructor Create( aParam: AlgumTipo );


e uma classe
TFilha = class( TPai )

aqui esta a minha duvida:
[b:33864a0647]Tem como criar o metodo costructor da classe Filha com parametros
diferentes da classe Pai e que execute o constructor da class Pai ?[/b:33864a0647]

exemplo:
constructor TFilha.Create ( aParam1, aParam2: OutroTipo );
begin
  inherited; // executa o constructor da classe Pai
  // ...
  // ...
end;



GOSTEI 0
Michael

Michael

21/09/2006

[quote:e8342319c5=´Fabiano Góes´]Tem como criar o metodo costructor da classe Filha com parametros
diferentes da classe Pai e que execute o constructor da class Pai ?[/quote:e8342319c5]
Sim. Apenas defina na classe filha o novo construtor desejado, exatamente como no exemplo que vc mesmo fez. A única coisa que não vai funcionar é a chamada a [b:e8342319c5]inherited [/b:e8342319c5]no construtor da classe filha, pois, como os parâmetros são diferentes, o compilador do Delphi não tem como saber como montar a assinatura do método na classe pai. Então vc tem que chamá-lo explicitamente:

constructor TFilha.Create(aParam1, aParam2: OutroTipo);
begin
  inherited Create(AlgumTipo); // executa o constructor da classe Pai 
...
end;


Se o construtor da classe-pai estiver marcado com a palavra-chave [b:e8342319c5]virtual[/b:e8342319c5], vc deve marcar o mesmo método na classe filha com a palavra-chave [b:e8342319c5]reintroduce[/b:e8342319c5], para remover o warning que o compilador vai gerar.

[]´s


GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

Marcos Salles escreveu: se é que eu entendi bem , sua duvida , acho que nao é aconelhavel , usar os metodo de uma classe para criar [b:2004bc055d]objetos de outras classes. [/b:2004bc055d]O correto é que esses objetos façam parte do atributos desta classes e devam ser instanciados no constructor e destruidos no destructor desta calsse [quote:2004bc055d]Isso depende, Marcos Salles. Há casos onde a criação de um objeto é custosa e só deve ser feita qdo realmente necessário. É o caso de um acesso a um banco de dados. Nessas situações, uma best practice é inicializar a variável com nil no construtor da classe, e no método que a utiliza, verificar a sua nulidade e instanciar o objeto de fato. No destrutor, ao chamar Free, não ocorrerá erro mesmo que o ponteiro ainda esteja nulo.
[/quote:2004bc055d]

particularidades e situaçoes que merecem atenção especial , sempre irão existir... Quando coloquei o modelo simplificado , foi na[b:2004bc055d] percepeção [/b:2004bc055d]que tive da pergunta do Fabiano.Goes e que vejo muita gente fazendo

Type TMinhaClasse = class .... public Constructor Create end;


No metodo constructor

Constructor MinhaClasse.Create; begin //o cara instancia um objeto de outra classe ... [b:2004bc055d]//não tem nenhum atributo na classe com relação[/b:2004bc055d] //a estes objetos umObjetoDeOutraClasse:=TOutraClasse.Cretae; end;


Var umObjetoMinhaClasse:TminhaClasse; begin umObjetoMinhaClasse:=TumObjetoMinhaClasse.Create; Aqui o cara destroe o objeto umObjetoMinhaClasse.Free; end;


a questão é:
quando eu destruir( destructor ) essa classe ( TClasse.Free; ) os objetos tambem serao destruidos ????


A resposta na minha opnião é não.. O objeto criado <umObjetoDeOutraClasse> ainda estara na memoria

esta foi a minha[b:2004bc055d] abstração [/b:2004bc055d]da duvida do Fabiano.Goes... Aonde tive como principal foco a parte dos[b:2004bc055d] Atributos [/b:2004bc055d]da Classe e não a localização em si da [b:2004bc055d]criação[/b:2004bc055d] desses Objetos.

é claro que este objetos serão na maior parte das vezes intanciados no metodo contructor da classe , mas voce apresentou um modelo , aonde por questões ´custodiosas´ , esta instanciação se dara num método da classe... Isto é , so ira instanciar , quando de fato necessitar desses objetos

Outro fato importante em sua colocação foi:

[b:2004bc055d]michael escreveu[/b:2004bc055d]
No destrutor, ao chamar Free, não ocorrerá erro mesmo que o ponteiro ainda esteja nulo.


porque mesmo que seja nil , se trata de um ponteiro válido...



O seu modelo veio a completar a minha opinião , e é bom que fique entendido , pois esses topicos são referencias para consultas posteriores. Portanto não podemos deixar um Grual de dúvida e nem de incertezas.


GOSTEI 0
Thomaz_prg

Thomaz_prg

21/09/2006

Também estou estudando um pouco de POO e ficaram algumas dúvidas com relação ao tópico, e gostaria da ajuda dos colegas...

1. Tipo, li em alguns artigos, que não é correto se ter nas classes objetos de ligação com o banco de dados... essa afirmação procede?

2. Como ficaria a montagem de uma classe, para a montagem de uma pesquisa por exemplo???

3. Li a respeito de campos de classe, porém não encontrei uma forma de fazer isso no delphi (7 pelo menos, pois no 2006 vi um exemplo, que testei no delphi 7 e não funcionou). Alguém saberia como implementar isso??

4. A respeito da utilização de classes e interface com o usuário... acham viável a utilização de ferramentas do tipo SnapDataset?? Ou preferem trabalhar com TFields??? Ou trabalhar apenas com a classe e componentes não dataaware? E pq?

5. Como ficaria o trabalho da criação das classes, na montagem de uma aplicação multicamadas (3 ou 4 camadas). As classes ficariam no cliente, na aplicação servidora ou em ambos?

Desculpem pelo excesso... sei que é muita coisa, mas é que, não sei muito sobre a área. Hoje, procuro implementar o que acredito ser mais ou menos correto, sobre POO, usando TFields, e componentes dataaware. Deixo as regras todas nos componentes. Mas não sei até que ponto isso está correto.


GOSTEI 0
Cesar Romero

Cesar Romero

21/09/2006

1. Tipo, li em alguns artigos, que não é correto se ter nas classes objetos de ligação com o banco de dados... essa afirmação procede?


Classes de Objetos não é o termo correto, mas eu acho que você se refere a Classes de Objetos de Regra de negócios. Sim você deve separar a Regra de negócio da ´persistência´.

2. Como ficaria a montagem de uma classe, para a montagem de uma pesquisa por exemplo???


A classe fica simples, a pesquisa fica por conta de um mecanismo de Persistencia, o qual apenas retorna um objeto pelo ID (Chave Primária) ou uma lista de objetos pelo critério.

3. Li a respeito de campos de classe, porém não encontrei uma forma de fazer isso no delphi (7 pelo menos, pois no 2006 vi um exemplo, que testei no delphi 7 e não funcionou). Alguém saberia como implementar isso??


Este código que você viu no Delphi 2006 não seria .NET? Então nunca funcionará no Delphi 7 Win32

4. A respeito da utilização de classes e interface com o usuário... acham viável a utilização de ferramentas do tipo SnapDataset?? Ou preferem trabalhar com TFields??? Ou trabalhar apenas com a classe e componentes não dataaware? E pq?


Quem desenvolve OO, prefere utilizar componente não dataware, utilizando design patterns, como MVP, para fazer a ligação dos componentes com as classes.
Os componentes Dataware foram criados para trabalhar com Datasets, datasource e TFields, não faz sentido utilizá-los pois eles fazem muita coisa desnecessária neste novo modelo, só iria ´inchar´ o código.

5. Como ficaria o trabalho da criação das classes, na montagem de uma aplicação multicamadas (3 ou 4 camadas). As classes ficariam no cliente, na aplicação servidora ou em ambos?

Eu separo classes entre servidor e cliente de acordo com a natureza da classe, em alguns casos em ambos, e por exemplo tendo um objeto de validação da classe em somente 1 dos lados.

Estou finalizando o desenvolvimento de um framework para POO que trata todas as fazes do desenvolvimento, se quiser dar uma olhada o link é www.liws.com.br/wiki

No momento estou trabalhando no MVP (parte visual) até o fim da semana devo ter uma nova versão com exemplos de telas de sistemas.

[]s


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

[quote:067d9aed06=´Marco Salles´]
O correto é que esses objetos façam parte do atributos desta classes e devam ser instanciados no constructor e destruidos no destructor desta classe
[/quote:067d9aed06]

Marco Salles, desculpe a minha iguinorancia mais gostaria mesmo de aprender um pouco sobre o assunto, por isso vou continura esse post.

um exemplo.
olha só, eu tenho uma classe:
type
  TDataBase = class
  private   
    FConnection: TADOConnection;
    FQryInsert: TADOQuery;
    FQryEdit: TADOQuery;
    FQrySearch: TADOQuery;
    ...
  public
    procedure Insert;
    procedure Edit; 
    procedure Search;  
  end;

constructor TDataBase.Create(AOwner: TComponent);
begin
  FConnection := TADOConnection.Create( nil );
  FQryInsert  := TADOQuery.Create( nil );
  FQryEdit    := TADOQuery.Create( nil );
  FQrySearch  := TADOQuery.Create( nil );
end;

destructor TDataBase.Destroy;
begin
  FConnection.Free;
  FQryInsert.Free;
  FQryEdit.Free;
  FQrySearch.Free;
  inherited;
end;



no OnCreate do Form eu instancio
procedure TfrmDefault.FormCreate(Sender: TObject);
begin
  DB := TDataBase.Create( self );
end;


no OnClose do Form eu Libero
procedure TfrmDefault.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DB.Free;
end;


se o Form for aberto e o usuario apenas fizer uma pesquisa todos os objetos seria instanciados sem a necessidade, neste caso seria melhor criar uma classe para cada necessidade ( Insert, Edit, Search ) ????

não sei se deu pra entender o meu Raciocínio, mais se der pra descutir sobre isso seria muito útil !!!
abraço !!!


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

[quote:8b655bba28=´Marco Salles´]se é que eu entendi bem , sua duvida , acho que nao é aconelhavel , usar os metodo de uma classe para criar objetos de outras classes
[/quote:8b655bba28]
Marco Salles, por isso que eu ´üsava metodos de uma classe criar criar outras classes´, tipo no metodo Insert da classe DataBase eu criava os objetos(Query, etc) e no final do Insert eu Liberava os objetos.


GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

mais se der pra descutir sobre isso seria muito útil !!! abraço !!!


vamos discutir sim...

voce leu a mensagem do michael e a minha replica ????

volte um pouco atras e ´releia´.....

segue aqui apenas um trecho...
[b:4a5b6ef29c]michael escreveu[/b:4a5b6ef29c]
Isso depende, Marcos Salles. Há casos onde a criação de um objeto é custosa e só deve ser feita qdo realmente necessário. É o caso de um acesso a um banco de dados.


[b:4a5b6ef29c]marco salles escreveu[/b:4a5b6ef29c]
esta foi a minha abstração da duvida do Fabiano.Goes... Aonde tive como principal foco a parte dos Atributos da Classe e não a localização em si da criação desses Objetos. é claro que este objetos serão na maior parte das vezes intanciados no metodo contructor da classe , mas voce apresentou um modelo , aonde por questões ´custodiosas´ [b:4a5b6ef29c], esta instanciação se dara num método da classe...[/b:4a5b6ef29c] Isto é , so ira instanciar , quando de fato necessitar desses objetos


[b:4a5b6ef29c]o que voce entendeu desta ´discusão´ [/b:4a5b6ef29c]??????

[b:4a5b6ef29c]fabiano escreveu [color=darkred:4a5b6ef29c]+/-[/color:4a5b6ef29c][/b:4a5b6ef29c]
se o Form for aberto e o usuario apenas fizer uma pesquisa todos os objetos seria instanciados sem necessidade. Neste caso seria melhor [b:4a5b6ef29c][color=darkred:4a5b6ef29c]criar metodos para instanciar estes objetos[/color:4a5b6ef29c][/b:4a5b6ef29c] de acordo com a necessidade ( Insert, Edit, Search ) ????


p:S [color=darkred:4a5b6ef29c]Alterei[/color:4a5b6ef29c] um pouquinho sua mensagem inical , por entende-la desse modo...


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

o que voce entendeu desta ´discusão´ ?????? [quote:5842b85631=´Fabiano Góes´] se o Form for aberto e o usuario apenas fizer uma pesquisa todos os objetos seria instanciados sem necessidade. Neste caso seria melhor criar metodos para instanciar estes objetos de acordo com a necessidade ( Insert, Edit, Search ) ????



p:S Alterei um pouquinho sua mensagem inical , por entende-la desse modo...
[/quote:5842b85631]

beleza, neste caso eu estava fazendo certo então.
um exemplo, imagine que nessa classe TDataBase, tenha um metodo´OpenConnection´:
function OpenConnection ( TADOConnection; ADataSource: String );
begin
  // criar o objeto de conexão
  FConnection := TADOConnection.Create( nil )
  try
    { aqui faz a abertura de conexao }
  finally
    FreeandNil( FConnection );
  end;
end;


[color=red:5842b85631]duvida[/color:5842b85631]: [b:5842b85631]se ocorrer algum erro na tentativa de abrir a conexao o ´FConnection ´ vai ser liberado da memoria ?[/b:5842b85631]


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

melhorando o exemplo acima:

procedure TDataBase.Search ( ATableName, AField, AParam: String );
begin
  // Cria objetos 
  FConnection := TADOConnection.Create( nil );
  FQrySearch  := TADOQuery.Create( nil );
  try
    OpenConnection( FConnection, FDataDource); // metodo para abertura da conexao
    { aqui faz o select, exibe os dados, etc }  
  finally
    FreeAndNil( FConnection  );
    FreeAndNil( FQrySearch   );
  end;
end;


[color=red:8757e681d2]duvida[/color:8757e681d2]: [b:8757e681d2]se ocorrer algum erro na tentativa de abrir a conexao o ´FConnection ´ vai ser liberado da memoria ?[/b:8757e681d2]


GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

Do jeito que voce esta fazendo , usando o try<bloco> Finally , [b:633ad2f14d]independemente[/b:633ad2f14d] de ocorrer um erro ou não na conexão os objetos
instanciados FConnection e FQrySearch serão liberados da memóriae e alem disso voce perde a referencia (var) com eles

Tem que levar em conta que no destructor desta classe voce libera esses objetos , que foram destruidos pela falha na conexão. Fazendo dessa forma , possivelmente voce tera um erro de [b:633ad2f14d]AV[/b:633ad2f14d]....

Se a idéia de usar essse modelo é instanciar esse objetos de acordo com a necessidade , porque então voce tem que destui-los ??? Não seria melhor tentar efetuar simplesmente a conexão novamente ...

lembre-se do que o michael disse:
no método que a utiliza, verificar a sua nulidade e instanciar o objeto de fato
.

quer dizer: no metodo que esta instanciado , voce Testa a anuidade , se for = nil (valor atribuido no constructor) da classe , voce instancia e faz a conexão... Se ocorrer um erro foce comunica e pergunta se quer tentar a conexão novamente... mas não destrua , porque a logica desse modelo que esta criação é ´custosa´


GOSTEI 0
Fabiano Góes

Fabiano Góes

21/09/2006

Baleza Marco Salles,

este post está sendo de muita valia pra mim, pois coisas simples que já são claras pra muitos, pra mim ainda existe algumas duvidas que muitas delas estão sendo esclarecidas aqui.

vou dar mais uma estudada em tudo que foi dito aqui, depois faço algum post tirar mais algumas duvidas :lol:

desde já agraço muito a sua atenção !!!


GOSTEI 0
Marco Salles

Marco Salles

21/09/2006

so para enfatizar bem e deixar claro , retirando qualquer reticencias que ainda persiste sobre :

´É boa norma de programação que um método constructor , ao construir uma instancia inicialize seus atributos. Entretanto , uma classe pode apresentar um metodo constructor que não inicialize explicitamente determinados atributos´


GOSTEI 0
POSTAR