67 public Periodo adiaUmaSemana() { Calendar novoFim = (Calendar) this.fim.clone(); novoFim.add(Calendar.DAY_OF_MONTH, 7); return new Periodo(inicio, novoFim); } E, com uma pequena modicao, podemos implementar o design pattern yweight em nossa classe, compartilhando a instncia do Calendar de incio do, perodo entre o objeto original e o novo, com uma semana adiada. Para tanto, precisaramos de um outro construtor privado para ser chamado no adiaUmaSemana que no zesse o clone. Utilizar classes imutveis traz um trabalho a mais junto com os diversos benefcios descritos. Voc deve considerar fortemente criar sua classe como imutvel. .. Cc:onoo com o moovto nNIm:co Um dos conceitos fundamentais da orientao a objetos o de que voc no deve expor seus detalhes de implementao. Encapsulando a implementao, podemos troc -la com facilidade, j que no existe outro cdigo dependendo desses deta- lhes, e o usurio s pode acessar seu objeto atravs do contrato denido pela sua interface pblica. 19
Costumeiramente, aprendemos que o primeiro passo nessa direo declarar todos seus atributos como private: public class Conta { private double limite; private double saldo; } Para acessar esses atributos, um desenvolvedor que ainda esteja aprendendo vai rapidamente cair em algum tutorial, que sugere a criao de getters e setters para poder trabalhar com esses atributos: public class Conta { private double limite; private double saldo; public double getSaldo() { return saldo; } ArqDesignSoftware_BOOK.indb 67 12/11/2011 14:48:44 68 Captulo 3. Tpicos de Orientao a Objetos public void setSaldo(double saldo) { this.saldo = saldo; } public double getLimite() { return limite; } public void setLimite(double limite) { this.limite = limite; } } Essa classe contm alguns mtodos que acabam por ferir as ideias do encap- sulamento. O mtodo setSaldo um bom exemplo disso, j que dicilmente o saldo em uma entidade Conta ser simplesmente substitudo por outro. Para alterar o saldo de uma conta, necessrio alguma operao que faa mais sentido para o domnio, como saques ou depsitos. Nunca crie um getter ou setter sem uma necessidade real; lembre -se de que precisamos que essa necessidade seja clara para criar qualquer mtodo que colo- camos em uma classe. Particularmente, os getters e setters so campees quando falamos em mtodos que acabam nunca sendo invocados e, alm disso, grande parte dos utilizados poderia ser substituda por mtodos de negcio. 20
Essa prtica foi incentivada nos primrdios do AWT, para o qual era reco- mendado criar getters e setters para serem invocados no preenchimento de cada campo visual da sua interface grca com o usurio, cunhando o termo JavaBean. Os EJBs tambm contriburam para esta prtica, como ser visto adiante. Criando classes desta forma, isto , adicionando getters e setters sem ser cri- terioso, cdigos como conta.setSaldo(conta.getSaldo() + 100) estaro espalhados por toda a aplicao. Se for preciso, por exemplo, que uma taxa seja debitada toda vez que um depsito realizado, ser necessrio percorrer todo o cdigo e modicar essas diversas invocaes. Um search/replace ocorreria aqui; pssimo sinal. Podemos tentar contornar isso e pensar em criar uma classe res- ponsvel por esta lgica: public class Banco { public void deposita(Conta conta, double valor) { conta.setSaldo(conta.getSaldo() + valor); } public void saca(Conta conta, double valor) { if (conta.getSaldo() >= valor) { ArqDesignSoftware_BOOK.indb 68 12/11/2011 14:48:44 3.5. Cuidado com o modelo anmico 69 conta.setSaldo(conta.getSaldo() - valor); } else { throw new SaldoInsuficienteException(); } } } Esse tipo de classe tem uma caracterstica bem procedural, fortemente si- nalizada pela ausncia de atributos e excesso do uso de mtodos como funes (deposita e saca poderiam ser estticos). Alm disso, pode -se dizer que esta classe tem uma intimidade inapropriada com a classe Conta, pois conhece demais sua implementao interna. Repare que o mtodo saca verica primeiro se o saldo maior que o valor a ser sacado, para, ento, retirar o dinheiro. Esse tipo de lgica deveria estar dentro da prpria classe Conta. O princpio do Tell, Dont Ask prega exatamente isso: voc deve dizer aos ob- jetos o que fazer (como sacar dinheiro), evitando perguntar em excesso o estado ao objeto, como getSaldo, e, a partir desse estado, tomar uma deciso. 21 Esse tipo de classe comumente encontrada e classicada como o pattern Business Object por concentrar a lgica de negcios. J a classe Conta, por ter apenas os dados, recebia o nome Value Object (hoje, este pattern tem outro sig- nicado). Da forma como est, temos separados nossos dados na classe Conta e a lgica de negcio na classe Banco, rompendo o princpio bsico de manter comportamento e estado relacionados em uma nica classe. o que chamamos de modelo anmico (anemic domain model), 22 no qual nossa classe Conta parece no ter responsabilidade alguma no sistema, nenhu- ma ao relacionada. necessrio uma classe externa, Banco, para dar alguma ao para nossa Conta, tratando-a quase como um fantoche. 23 Com isso, a classe Banco conhece detalhes da implementao da classe Conta e, se esta mudar, Banco muito provavelmente mudar junto. Podemos unir a lgica de negcio aos dados de uma maneira simples, inse- rindo mtodos na classe Conta e removendo os que apenas acessam e modicam diretamente seus atributos: public class Conta { private double saldo; private double limite; public Conta(double limite) { this.limite = limite; } ArqDesignSoftware_BOOK.indb 69 12/11/2011 14:48:44 70 Captulo 3. Tpicos de Orientao a Objetos public void deposita(double valor) { this.saldo += valor; } public void saca(double valor) { if (this.saldo + this.limite >= valor) { this.saldo -= valor; } else { throw new SaldoInsuficienteException(); } } public double getSaldo() { return this.saldo; } } Aqui mantivemos o getSaldo, pois faz parte do domnio. Tambm adicio- namos algumas manipulaes ao mtodo saca, e poderamos debitar algum imposto em cima de qualquer movimentao nanceira no mtodo deposita. Enriquea suas classes com mtodos de negcio, para que no se tornem apenas estruturas de dados. Para isso, cuidado ao colocar getters e setters in- discriminadamente. Devemos encapsular os dados em atributos de objetos e, ainda, lembrar que a orientao a objetos prega a troca de mensagens (invocao de mtodos) de maneira a concentrar as responsabilidades a quem pertence os dados. O prprio Alan Key, que cunhou o termo programao orientada a objetos, ressalta que o termo foi uma m escolha, pois diminui a nfase da ideia mais importante, a troca de mensagens. 24 possvel seguir a mesma linha para entidades do JPA/Hibernate, vericando a real necessidade dos getters e setters. Por exemplo, a necessidade de um mtodo setId para a chave primria torna -se discutvel no momento em que um framework utiliza reection ou manipulao de bytecode para ler atributos privados. Algumas vezes, os getters e setters so, sim, necessrios, e alguns patterns at mesmo precisam de uma separao de lgica de negcios dos respectivos dados. 25 Prticas como o Test Driven Development podem ajudar a no criar mtodos sem necessidade. Porm, frequentemente, entidades sem lgica de negcio, com compor- tamentos codicados isoladamente nos business objects, caracterizam um modelo de domnio anmico. muito fcil terminar colocando a lgica de negcio, que poderia estar em em nossas entidades, diretamente em Actions do Struts Actions do Struts, ActionListeners do Swing e managed beans do JSF, ArqDesignSoftware_BOOK.indb 70 12/11/2011 14:48:44 3.6. Considere Domain -Driven Design 71 transformando -os em transaction scripts. Este modelo acaba cando com um forte apelo procedural e vai diretamente na contramo das boas prticas de orientao a objetos e do Domain -Driven Design. 19,26 .o. CoNs:ovnv Domn:N -Dn:vvN Dvs:cN Todo soware desenvolvido com um propsito concreto, para resolver problemas reais que acontecem com pessoas reais. Todos os conceitos ao redor do problema a ser resolvido so o que denominamos domnio. O objetivo de toda aplicao resolver as questes de um determinado domnio. Domain -Driven Design (DDD) signica guiar o processo de design da sua aplicao pelo domnio. Parece bvio, mas muitos sowares no so projetados de acordo com o domnio em que atuam. Podemos perceber essa realidade analisando o cdigo de diversos sistemas atuais, nos quais as entidades no condizem com a realidade dos usurios e so de difcil entendimento. 26,22 Segundo o DDD, impossvel resolver o problema no domnio do cliente sem entend -lo profundamente. claro que o desenvolvedor no quer se tornar um completo especialista na rea do cliente, mas deve compreend -la o suciente para desenvolver guiado pelo domnio. Para isto acontecer, o ponto -chave a conversa. Conversa constante e profun- da entre os especialistas de domnio e os desenvolvedores. Aqueles que conhecem o domnio em detalhes devem transmitir conhecimento aos desenvolvedores. Juntos, chegaro a termos e vocbulos em comum, uma lngua comum, que todos utilizem. a chamada Lngua Ubqua (Ubiquitous Language). Esta lngua baseada nos termos do domnio, no totalmente aprofundada neste, mas o suciente para descrever os problemas de maneira sucinta e completa. Durante a conversa constante, cria -se um modelo do domnio (ou Domain Model). uma abstrao do problema real, que envolve os aspectos do domnio que devem ser expressados no sistema, desenvolvida em parceria pelos especia- listas do domnio e desenvolvedores. este modelo que os desenvolvedores im- plementam em cdigo, que deve ocorrer literalmente, item por item, como foi acordado por todos. Isto possibilita o desenvolvimento de um cdigo mais claro, e, principalmente, que utiliza metforas prprias do domnio em questo. Seu programa deve expressar a riqueza do domain model. Qualquer mudana no modelo deve ser reetida no cdigo. Caso o modelo se torne invivel para se implementar tecnicamente, ele deve ser mudado para se tornar implementvel. ArqDesignSoftware_BOOK.indb 71 12/11/2011 14:48:45