Você está na página 1de 5

3.5.

Cuidado com o modelo anmico


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