Baixe o app para aproveitar ainda mais
Prévia do material em texto
Blog Java Rails Agile Web Design Arquitetura Inovação Revisitando a Orientação a Objetos: encapsulamento no Java Postado em 14. jun, 2012 por Mauricio Aniche em Arquitetura, Java Tweet 40 Façamos uma aposta. Tenho certeza que você, ao ver a classe abaixo, consegue perceber um problema nela: Sim. Os atributos estão todos públicos! Isso vai exatamente contra uma das nossas primeiras lições quando aprendemos Java: atributos devem ser privados e precisamos de getters e setters para acessá-los. Vamos então fazer essa mudança no código. Agora está melhor, certo? Ainda não. Deixamos escapar na verdade o grande princípio que está por trás da ideia de colocar atributos como privados. Do jeito que a classe Pedido está nesse momento, podemos fazer coisas como: Mas aonde está o problema? Imagine outras 10 classes que fazem a mesma coisa: de alguma forma, elas manipulam o valor total do pedido. Agora imagine que a regra de negócio do pedido mude: todo item comprado ganha desconto de 5% se o valor dele for superior a 1000 reais. Implementar essa mudança não será tarefa fácil. Precisaríamos fazê-la em diferentes classes do sistema. Buscar Caelum | Newsletter | Apostilas | Compartilhar class Pedido { public String comprador; public double valorTotal; // outros atributos } class Pedido { private String comprador; private double valorTotal; // outros atributos public String getComprador() { return comprador; } public void setComprador(String comprador) { this.comprador = comprador; } public double getValorTotal() { return valorTotal; } public void setValorTotal(double valorTotal) { this.valorTotal = ValorTotal; } // outros getters e setters } Pedido p = new Pedido(); // muda valor do pedido para 200 reais! p.setValorTotal(p.getValorTotal() + 200.0); Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 1 de 8 27/2/2013 07:17 Quanto tempo demoraremos para mudar o sistema? Não sabemos exatamente aonde devemos fazer as mudanças já que elas estão espalhadas pelo código. Esse, aliás, é um dos grandes problemas de códigos legados: uma simples mudança precisa ser feita em tantas classes e, na prática, sempre esquecemos algum ponto, e nosso sistema frequentemente quebra. A classe Pedido não foi bem desenhada. Demos acesso direto ao atributo valorTotal, um atributo importante da classe. Veja que o modificador private nesse caso não adiantou de nada, já que demos também um setter para ele. Vamos tentar diminuir o acesso ao atributo, criando métodos mais claros para a operação de depósito: Agora, para adicionarmos um item no Pedido, faremos uso desse novo comportamento: Mas qual a diferença entre os dois códigos abaixo? Veja que na primeira linha de código, sabemos exatamente COMO funciona a adição de um novo ítem no pedido: devemos pegar o valor total e somar o valor novo com desconto de 5% se ele for maior que 1000. Já na segunda linha de código, não sabemos como esse processo funciona. Quando sabemos O QUÊ um método faz (igual ao método adiciona, sabemos que ele adiciona um ítem no pedido, por causa do nome dele), mas não sabemos exatamente como ele faz, dizemos que esse comportamento está encapsulado! A partir do momento que as outras classes não sabem como a classe principal faz o seu trabalho, significa que as mudanças ocorrerão apenas em um lugar! Afinal, elas estão escondidas (encapsuladas)! class Pedido { private String comprador; private double valorTotal; // outros atributos public String getComprador() { return comprador; } public double getValorTotal() { return valorTotal; } public void adiciona(Item item) { if(item.getValor() < 1000) this.valorTotal += item.getValor(); else this.valorTotal += item.getValor() * 0.95; } } Pedido p = new Pedido(); p.adiciona(new Item("Chuveiro Elétrico", 500.0)); Item item = new Item("Super Geladeira", 1500.0); // antiga if (item.getValor() > 1000) { c1.setValorTotal(c1.getValorTotal() + item.getValor() * 0.95); } else { c1.setValorTotal(c1.getValorTotal() + item.getValor()); } // nova c1.adiciona(item); Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 2 de 8 27/2/2013 07:17 Mauricio Aniche (Google+) Ou seja, para implementar a regra de negócios nova, bastaria mexermos em um único lugar: No fim, a real utilidade do private é esconder acesso de atributos que precisam ser acessados de maneira mais inteligente. Mas veja que de nada adianta colocar todos os atributos como private e criar getters e setters para todos eles. Deixamos o encapsulamento “vazar” do mesmo jeito. Esconda os atributos, mas pense em comportamentos inteligentes para acessá-los. Uma ótima maneira para saber se o comportamento está encapsulado é olhar para o código que faz uso dele! Se conseguirmos dizer o que o método faz, mas sem dizer como ele faz, então podemos afirmar que o comportamento está encapsulado! Muitas vezes deixamos esses princípios passarem. Se quiser revisitar essas e outras boas práticas de Orientação a Objetos junto com os instrutores da Caelum, há mais posts por aqui, como um específico sobre esse problema dos getters e setters, o excesso de ifs e o relacionamento bidirecional entre classes. Quer praticar tudo isso com video aulas, respostas dos instrutores e correção dos seus exercícios? Confira nosso novo curso online de boas práticas de orientação a objetos!. Tweet 40 Tags: boas práticas, encapsulamento, fj-11, fj-15, getters e setters, orientação a objetos 32 Respostas para “Revisitando a Orientação a Objetos: encapsulamento no Java” Rodrigo Ferreira 14. jun, 2012 Excelente post Mauricio! Bem simples de entender. É uma pena que ainda existam programadores java que acham que encapsulamento se resume a atributos private e métodos get/set público. 1. Rafael Rossignol 14. jun, 2012 Concordo em todos os aspectos, porém os frameworks/apis de persistência nos obrigam a implementar getters e setters pra todos os atributos que são persistidos, portanto, esse controle de encapsulamento ainda tem q estar na nossa cabeça, já que não podemos deixar de implementar o setter 2. Anderson Souza 3. public void adiciona(Item item) { if (item.getValor() > 1000) this.valorTotal += item.getValor(); else this.valorTotal += item.getValor() * 0.95; // nova regra de negócio aqui } Compartilhar Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 3 de 8 27/2/2013 07:17 14. jun, 2012 Muito bom artigo! Só uma dúvida, se a regra diz que todos produtos com valor maior do R$ 1.000,00 recebe desconto, o ‘if’ do código da classe Pedido não está invertido? Carlos Antônio. 14. jun, 2012 Exelente post, está modo deve ser ótimo para JAVA, mas com certeza se encaixa muito bem em PHP e outras linguagens… 4. Leonardo Nunes 14. jun, 2012 Ótimo artigo! 5. Edinei 14. jun, 2012 Muito bom post !!! É muito comum vermos isso no dia a dia, criar o atributo gerar os getter/setter (normalmente pela IDE) sem ao menos saber se de fato esses atributos deveriam ser acessados diretamente pelo cliente. Onde na verdade métodos voltados para a lógica de negócio seriam os mais indicados. Acontece bastante isso também quando usamos collection em nossas classes e temos um set(Collection) e um getCollection expondo demais as estruturas internas de um objeto, além de permitir os clientes manipularem o conteúdo das coleções diretamente sem ser o “dono” dessas collections. Martin Fowler mostra isso no seu livro de Refactorings, para quem quiser ver: http://sourcemaking.com/refactoring/encapsulate-collection 6. RafaelPonte 14. jun, 2012 Como sempre muito simples e didático ao escrever sobre design de software – assunto este que sempre me chamou a atenção. Só faltou você comentar que um código com encapsulamento bem definido pode ser facilmente testado através de testes de unidade. Um post que também vale muito a pena ler é o post que o Phillip Calçado (aka Shoes) escreveu em 2008, http://blog.fragmental.com.br/2008/05 /18/objetos-nao-sao-atributos-funcoes/ . Ah, como o Anderson Souza comentou, o if() do método adiciona() está invertido. @RafaelRossignol Na verdade já faz alguns bons anos que frameworks de persistência não te obrigam a ter getters e setters, como o Hibernate por exemplo. Contudo, a maioria gritante dos frameworks MVC te obrigam a seguir o padrão JavaBeans, ou seja, você precisará de getters e setters. No mais, excelente post, Aniche 7. jonas 14. jun, 2012 Parabéns pelo post Mauricio Aniche 8. Mauricio Aniche 14. jun, 2012 Olá galera, obrigado! Fico feliz que gostaram! @Rafael Rossignol Sim, infelizmente esse é um problema sério que temos: a infra-estrutura influenciando no nosso projeto de classes. Isso não deveria acontecer. 9. Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 4 de 8 27/2/2013 07:17 Como citado acima, o Hibernate hoje até que não te força tanto, mas a maioria dos frameworks MVC pedem que vc tenha getters/setters nos seus objetos. A sacada é pensar em como lidar com isso. Momento plin-plin: O VRaptor te permite receber os dados pelo construtor, e assim você não precisa de setters aonde não quer. Mas concordo em abosluto com teu ponto! Mauricio Aniche 14. jun, 2012 Ah, e obrigado pessoal, o if estava invertido mesmo! Já arrumei! “Cadê o teste desse código, Aniche!?” 10. Felipe 14. jun, 2012 Excelente, Maurício ! Amigo, posso utilizar esse conteúdo para uma aula que vou dar ? Colocarei a fonte do seu site 11. Mauricio Aniche 14. jun, 2012 Oi Felipe, Claro que pode! Fico feliz que tennha gostado! Um abraço! 12. Herbert 14. jun, 2012 Sei que para bom entendedor, meia palavra basta. Mas nas primeiras linha de código existe um minúsculo erro: Pedido c1 = new Pedido(); // muda valor do pedido para 200 reais! c.setValorTotal(c.getValorTotal() + 200.0); Foi criado objeto c1 e não c. Muito bom o artigo, parabéns mais uma vez. 13. Mauricio Aniche 14. jun, 2012 Corrigido, Herbert! 14. Herbert 14. jun, 2012 só falta mudar o c.getValorTotal() para p.getValorTotal() também. Acho que não foi a toa que meu apelido no curso FJ11 era de “compilador”. Abraços e parabéns novamente. 15. Guilherme Mastria 14. jun, 2012 mas não é pra isso que utilizamos a classe de negócio? instanciando uma DAO, convém colocar esse tipo de verificação dentro de um bean?? abraço 16. Mauricio Aniche17. Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 5 de 8 27/2/2013 07:17 15. jun, 2012 Oi Guilherme, Por classes que negócio, vc quer dizer aquelas camadas onde enfiamos somente as regras de negócio, conforme sugerido por aquele catálogo de padrões da Sun? Infelizmente esses padrões promovem más práticas de código. Separar “regras de negócio” em uma camada e “dados” em outra, é voltar a programar de maneira procedural! E já sabemos os problemas desse paradigma: repetição de código, manutenção em diversos pontos diferentes, pois tudo está longe, e assim por diante. A discussão é parecida com a dos comentários acima. A infra estrutura sempre nos empurra a fazer mau uso da OO. Devemos lutar contra isso! Respondi? Gilmar M. dos Santos 15. jun, 2012 O post é muito bom, mas nada adianta saber disso, ser os frameworks mvc nos obrigado a implementar getters e setters. 18. Paulo Vinícius Moreira Dutra 15. jun, 2012 Excelente post. Sempre presei o uso dos bons princípios da orientação a objetos. É uma pena ainda alguns frameworks nos obrigarem a usar métodos getters e setters sem realmente ser necessário. Um bom sistema OO, concerteza será mais fácil de dar manutenção. E vamos utilizar o métodos getters e setters com moderação. 19. Luiz 15. jun, 2012 Maurício, Ótimo post. 20. Luis Vasconcellos 15. jun, 2012 Perfeito. A ideia é encapsular dados e expor comportamento ! 21. Antonio Cesar 16. jun, 2012 Independente de frameworks e especificações que nos obrigam a utilizar “Más Práticas” um bom post e uma discussão inteligente sobre boas práticas são sempre muito bem vindas…. Excelente post que estimula e valoriza o conhecimento bem utilizado… Parabéns…. 22. Raphael Lacerda 18. jun, 2012 Galera, apesar da maioria dos frameworks nos obrigarem a implementar os setters, vale lembrar que existem alternativas http://www.guj.com.br/java/208491-iogi—usando-objetos-imutaveis-junto-com-o-vraptor Excelente post… principalmente para quebrar mitos sobre atributos privados.. o q eu fico pé da vida é q os analista de mais alto nível dizem que o software precisa ter manutenibilidade… agora, como vc vai explicar para o cidadao que encapsular sem usar setter vai te ajudar nesse quesito??? 23. Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 6 de 8 27/2/2013 07:17 Enfim, dae o q acontece na maioria dos projetos é q fica uma história para ingles ver… o cara pede manutebilidade e o programador diz q fez um codigo totalmente manutivel seguindo os conceitos de “encapsulamento” Mauricio de Mello 18. jun, 2012 A Ideia básica de um bom código é não repetir código, seja em java, c# ou linguagens não orientadas a objetos. Ótimo post!! 24. Henrique S. 26. jun, 2012 Excelente post! 25. Rafael 28. jun, 2012 Parabens pelo otimos post. 26. Guilherme Mastria 03. jul, 2012 …depende de empresa para empresa e principalmente dos canais de acesso que aquela DAO vai ter! Se você tiver o seu sistema simplesmente Web, ok, tudo bem não ter o BO, mas você deixa o sistema altamente acoplado, ou seja, caso o seu sistema necessite de uma integração com outro de uma empresa (que comprou a sua ou foi adquirida por) ou simplesmente seja acessado por um mobile, TV digital, Web e Desktop, e com regras distintas… como o você faria? rs E hoje isso é bem propício. 27. Mauricio Aniche 04. jul, 2012 Oi Guilherme, Se você ainda não consegue trafegar a própria entidade de um lado pro outro (serializando em XML, JSON, ou coisa do tipo), aí vc cria uma classe que só tem atributos e só serve unica e exclusivamente para navegar de um lado pro outro (os famosos DTOs). Esconda a “sujeira” de converter sua entidade em um DTO, e pronto. Mas veja que essas classes não terão regra de negócio nenhum e só servirão para transferir dados de uma camada para outra. Faz sentido? 28. Hélio Moura 23. jul, 2012 Muito bem colocado este seu exemplo Maurício. Ótimo para aulas de orientação a objetos. Saliento ainda que o uso de DDD (Domain Driven Design) vem crescendo justamente por permitir que boas práticas como esta possam ser aplicadas. O uso de DDD permite ao analista/desenvolvedor isolar de fato a camada de negócio, camada esta que é composta por classes completas, isto é, com suas propriedades e comportamentos. Este isolamente evita ter que se criar métodos de acesso às propriedades exigidos por certos frameworks, evitando assim, a quebra do encapsulamento. Venho utilizando DDD ultimamente e isto me tem remetido às origens da teoria da orientação a objetos onde o quê se procurava era apenas oque hoje chamamos de boas práticas na orientação a objetos. Vocês da Caelum fazem um excelente trabalho!29. Mauricio Aniche 23. jul, 2012 Oi Hélio, Obrigado! E concordo com vc: DDD faz o programador relembrar da boa e velha OO! Um abraço, Mauricio 30. Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 7 de 8 27/2/2013 07:17 Andre Alves Pinto 16. ago, 2012 Valeu Maurício! 31. Maicon 19. ago, 2012 Parabéns pelo post Mauricio!! Explicou de forma simples e objetiva. abraços 32. Deixar uma Resposta ASSINE NOSSO RSS Facebook Destaques Por uma Web mais rápida: 26 técnicas de otimização de Sites As Novidades do Eclipse Juno Use CDI no seu próximo projeto Java Flexibilidade em páginas para dispositivos móveis com media queries Como não aprender Java e Orientação a Objetos: getters e setters Usando o Google Maps e GPS no Android Pixels, pixels ou pixels? Dicas de Web Mobile com viewport Entenda os MVCs e os frameworks Action e Component Based Os 7 hábitos dos desenvolvedores Hibernate e JPA altamente eficazes As novidades do Hibernate 4 Siga-nos no Twitter Caelum RSS Newsletter Contato Revisitando a Orientação a Objetos: encapsulamento no Java | blog.cae... http://blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsul... 8 de 8 27/2/2013 07:17
Compartilhar