none
Modelagem de Classes e Instância de Objetos. RRS feed

  • 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
    terça-feira, 6 de outubro de 2009 20:07

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
    quinta-feira, 8 de outubro de 2009 11:35

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
    terça-feira, 6 de outubro de 2009 22:00
  • 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);
                    }
    terça-feira, 6 de outubro de 2009 23:32
  • 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
    quarta-feira, 7 de outubro de 2009 00:55
  • 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
    quarta-feira, 7 de outubro de 2009 10:20
  • 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
    quarta-feira, 7 de outubro de 2009 13:00
  • 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
    quarta-feira, 7 de outubro de 2009 13:40
  • 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
    quarta-feira, 7 de outubro de 2009 15:18
  • 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
    quarta-feira, 7 de outubro de 2009 15:27
  • 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
    quarta-feira, 7 de outubro de 2009 22:54
  • 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
    quarta-feira, 7 de outubro de 2009 23:20
  • 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
    quinta-feira, 8 de outubro de 2009 11:35
  • 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

    quinta-feira, 8 de outubro de 2009 12:42