Usuário com melhor resposta
Modelagem de Classes e Instância de Objetos.

Pergunta
-
Pessoal,
na modelagem de Classes podemos utilizamos outras Classes como propriedades, correto? Ou seja, não é errado por exemplo criar uma classe Endereco uma Classe Telefone uma Classe Email e utilizar estas Classe como Propriedades de uma Classe Cliente, ou é uma baita besteira?
Pergunto isso, pois estou modelando assim, mas estou vendo que terei um custo altissimo de performance, pois para Instanciar um objeto Cliente obrigatóriamente tenho que ter um Construtor tipo:
Public Cliente() { this.Endereco = New endereco(); this.Telefone = New telefone(); this.Email = New email(); }
Ou seja, ao utilizar um datareader para preencher uma Lista de Clientes, para cada cliente o costrutor tem que ser chamado e dar um New para cada uma das minhas propriedades, e pior será caso estas classes também tenham construtores com outros objetos.
Como vocês modelam suas Classes de negócios utilizam apenas propriedades scalares Tipo: int, string, etc?
Num cenário como este, para preencher uma listagem com 500 Clientes o sistema levaria uma "eternidade", como vocês fazem?
Edmilson
Respostas
-
Edmilson,
Para utilizar o lazy loading a sua camada de DTO precisará da DAL, mas você não vai conseguir fazer isso simplesmente fazendo referência de projeto, você precisará implementar IoC.public class Cliente { private Endereco _endereco; private IDaoEndereco daoEndereco; public Endereco Endereco { get { if (_endereco == null) _endereco = daoEndereco.ObterEnderecoPorCliente(this.IdCliente); return endereco; } set { endereco = value; } } } public class DaoEndereco : IDaoEndereco { public Endereco ObterEnderecoPorCliente(int idCliente) { } }
Para obter uma instância do seu Dao de endereço no seu DTO você pode utilizar alguns frameworks como o Unit Application Block (recomendo o webcast do Giovanni https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=pt-BR&EventID=1032423368&CountryCode=BR) ou o Spring.Net.
Eduardo Silva
http://eduardodotnet.blogspot.com- Marcado como Resposta EdmilsonSilva quinta-feira, 8 de outubro de 2009 12:43
Todas as Respostas
-
Edmilson,
Sim podemos utilizar outras classes como atributos/propriedades de uma classe.
Para evitar esse problema de performance com algumas propriedades você pode aplicar Lazy Loading como uma forma de resolver o problema (http://martinfowler.com/eaaCatalog/lazyLoad.html), ou seja, só carregar as propriedades quando você precisar.
Eduardo Silva
http://eduardodotnet.blogspot.com -
Eduardo, grato pela resposta,
certamente é isso que eu necessito fazer para evitar a perda de performance da minha aplicação ao carregar a lista de Clientes, só tem um problema, não faço idéia de como implementar o Lazy Load, e o link não tem um exemplo pratico, como já citei estou usando ADO.NET (datareader para ser especifico) para carregar os objetos, será que é possivel fazer seguindo a mesma linha de desenvolvimento ou tenho que mudar toda minha abordagem?
Caso você tenha, ou possa postar algum exemplo ficarei grato.
Edmilson
Abaixo o trecho onde utilizo o datareader para preencher a lista de Clientes, para cada new o costrutor é chamado...
while (dr.Read()) { Model.Cliente objCliente = new Model.Cliente(); objCliente.idCliente = dr.GetInt32(0); objCliente.razaoSocial = dr.GetString(2); objCliente.cnpjCpf = dr.GetString(3); objCliente.datacadastro = dr.GetDateTime(13); listaCliente.Add(objCliente); }
-
Edmilson,
Primeiro, você realmente esta tratando e-mail, telefone e endereço como classes? Se sim, por que?
Segundo, não recomendo você utilizar lazy loading em todas as propriedades de sua classe, recomendo que você aplique nos cenários onde realmente é constatado o problema de performance.
Sendo simplista a aplicação do padrão seria algo mais ou menos assim:private Endereco _endereco; public Endereco Endereco { get { if (_endereco == null) _endereco = MeuRepositorio.ObterEnderecoPorCliente(this.IdCliente); return endereco; } set { endereco = value; } }
A implementação vai depender da sua arquitetura. Se você utilizar um ORM, como NHibernate por exemplo, esse recurso é mais fácil de ser implementado.
Eduardo Silva
http://eduardodotnet.blogspot.com -
Eduardo, grato pela resposta.
Acredito que a maneira como estou modelando as classes é que esta incorreta, eu estou sim colocando Endereco, Email e Telefone como Classes, meu objetivo seria reutilizar estas classes dentro de outras classes como Cliente, Funcionario, Contato, mas pelo visto o melhor é coloca-los como propriedades scalares, senão a performance caíra muito no preenchimento de List<T>, como vc modelaria estas classes?
grato,
Edmilson -
Edmilson,
Não consegui entender como você teria a reutilização transformando Endereco, Email e Telefone em classes já que ficaria algo +ou- assim:
public class Cliente { private Telefone _telefone; public Telefone Telefone { get { return _endereco; } set { _endereco = value; } } } public class Funcionario { private Telefone _telefone; public Telefone Telefone { get { return _telefone; } set { _telefone = value; } } }
Você pode ter reaproveitamento se você utilizar herança:
public abstract class Pessoa { private string _email; private string _telefone; private string _endereco; public string Email { get { return _email; } set { _email = value; } } public string Telefone { get { return _telefone; } set { _telefone = value; } } public string Endereco { get { return _endereco; } set { _endereco = value; } } } public class Cliente : Pessoa { // atributos, propriedades e métodos específicos de cliente } public class Functionario { // atributos, propriedades e métodos específicos de funcionário }
Mas veja a herança é uma sugestão e não uma regra para resolver esse tipo de problema ok?
Eduardo Silva
http://eduardodotnet.blogspot.com -
Olá Edmilson,
Primeiramente acho que realmente você deve fazer o Lazy Loading para todas as propriedades que forem retornar listas de objetos, e digo que geralmente faço dessa forma também. Também acho que você deve aplicar os conceitos de herança sugeridos pelo Eduardo, vão te ajudar muito na otimziação e organização do código.
Por último quero falar que, sempre utilizo propriedades dessa maneira em meus projetos, e ao longo de tempo ja tive várias dúvidas se era a melhor maneira de se fazer ou não, e o que sempre é um fator determinante para a escolha entre retornar listas de objetos ou simplesmente uma string ou id é em que eu vou utilizar os valores retornados.
Se voccê vai listar em um data grid todos os emails de um Cliente por exemplo, com certeza a melhor abordagem é que sua propriedade retorne uma lista de objetos emails que irá popular o grid, entretanto, se você irá utilizar a propriedade email somente para salvar no banco de dados, utilize somente um array com os IDs dessa entidade.
Para cada caso devemos analizar a melhor abordagem para o que realmente iremos utilizar aquele código, não existe uma maneira certa ou uma maneira errada, entretanto é sempre certo pensar na performance de seu código e também aplicar as técnicas de melhores práticas como Herança e Lazy Loading.
Abraços!
Michael M. Lima
MCTS: WSS 3.0 Config/Dev | MOSS 2007 Config/Dev
mlimablog.spaces.live.com | www.CanalSharePoint.com.br -
Eduardo, era exatamente isso que eu estava fazendo, minha modelagem estava assim:
Public Class Email { Public int idEmail {get; set;} Public string email {get; set;} } Public Class Endereco{ Public int idEndereco {get; set;} Public string endereco{get; set;} } Public Class Cliente { Public string nome {get; set;} Public Email email {get; set;} Public Endereco enderecol {get; set;} Public Cliente() { this.email = new Email(); this.endereco = new Endereco(); } }
O reaproveitamento era poder acessar os atributos da outra classe colocando o ponto tipo: objCliente.Email.idEmail, mas isso não ajuda em quase nada no momento. Observe que sempre que necessitar instanciar um cliente tenho que chamar o constutor para dar um New endereco e um new Email para ele, usando ADO.NET + Datareader carregar uma lista com 500 clientes tem um custo de performance rezoavel, por isso mudei as classes por propriedades simples.
grato,
Edmilson -
Michel, grato pela dica,
tenho algumas classe que terão realmente lists como propriedades, é o caso da Classe Estado que terá um List<Cidade>, mas realmente não sei como implementar o Lazy Load com ADO.NET + Datareader, se vc puder postar um pequeno trecho de exemplo ficarei grato.
Edmilson -
Edmilson,
conforme citei em alguns posts acima a implementação do lazy loading vai depender de como esta dividido as suas camadas lógicas.
Se você der mais detalhes de como esta a arquitetura da sua aplicação será mais fácil de lhe propor uma solução.
Eduardo Silva
http://eduardodotnet.blogspot.com -
Eduardo, sei que os mais Seniors e Arquitetos que lerem este post vão torcer o nariz, mas ainda não estou preparado para o desenvolvimento de uma grande arquitetura de OO, por isso ainda estou utilizando o já ultrapassado modelo anêmico UI/BLL/DAL/DTO, que também e tido como procedural. Estou fazendo tudo na mão sem utilizar nenhum ORM. Estou fazendo com ADO.NET puro.
grato,
Edmilson -
Edmilson,
Para utilizar o lazy loading a sua camada de DTO precisará da DAL, mas você não vai conseguir fazer isso simplesmente fazendo referência de projeto, você precisará implementar IoC.public class Cliente { private Endereco _endereco; private IDaoEndereco daoEndereco; public Endereco Endereco { get { if (_endereco == null) _endereco = daoEndereco.ObterEnderecoPorCliente(this.IdCliente); return endereco; } set { endereco = value; } } } public class DaoEndereco : IDaoEndereco { public Endereco ObterEnderecoPorCliente(int idCliente) { } }
Para obter uma instância do seu Dao de endereço no seu DTO você pode utilizar alguns frameworks como o Unit Application Block (recomendo o webcast do Giovanni https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=pt-BR&EventID=1032423368&CountryCode=BR) ou o Spring.Net.
Eduardo Silva
http://eduardodotnet.blogspot.com- Marcado como Resposta EdmilsonSilva quinta-feira, 8 de outubro de 2009 12:43
-
Eduardo, ai a coisa vai começando a ficar mais complexa do que eu gostaria, já vou ter que aplicar padrão Ioc já vou ter que utilizar outros frameworks, é mais simples trocar as propriedades que são Classes por proriedades simples scalares: string, int, etc. E quando eu necessitar de uma lista de qualquer um dos meus objetos eu crio a lista na minha camada DAL e chamo pelo parametro que eu quiser.
Por enquanto ainda estou na filisofia KISS (keep it simple).
Grato mesmo pelas dicas e pela ajuda, Valeu!
Edmilson