Você está na página 1de 5

Identificando e Convertendo Código Orientado a Objetos

e Código Procedural
Por Phillip Calçado “Shoes”

Como programadores Java, ouvimos falar todo dia na tal Orientação a Objetos. Se você já
frequentou uma faculdade, certamente teve aulas teóricas e práticas sobre estes conceitos. Se
estamos tão cercados de objetos por todos os lados neste ramo, porque não sentimos tanto as
vantagens que este paradigma afirma ter?

Um dos motivos é porque a grande maioria dos sistemas desenvolvidos em Java não
são orientados a objetos de verdade. Geralmente aprendemos a programar primeiro de
maneira estruturada, pensando em funções que manipulam estruturas de dados, e não é fácil
para pensarmos de uma maneira completamente diferente como OO precisa.

Neste breve artigo vamos dar uma olhada em como podemos identificar um código com
características procedurais e como podemos converter nossa lógica em algo mais fortemente
Orientado a Objetos.

Como Identificar Código Procedural


Código procedural tem características bem específicas. Ao pensar de maneira estruturada, nós
enxergamos o mundo (ou pelo menos o mundo do ponto de vista da nossa aplicação) como
um conjunto de estruturas de dados que são manipuladas por funções.
Numa linguagem procedural como C ou Pascal, isso seria representado com um struct ou um
register sendo manipulado por funções ou procedimentos. E em Java, como alguém consegue
escrever um programa Procedural?
A primeira pista é olhar a documentação do sistema. Se o sistema começou a ser pensado pelo
banco de dados, começou procedural. Num sistema Orientado a Objetos você deveria se
preocupar em primeiro lugar com como os objetos se relacionam e qual seu comportamento,
não em qual tabela vai ficar o nome do usuário!
Passando da documentação, vamos olhar o código. Neste tipo de sistema são comuns classes
como essa:
public class Aluguel {
private Collection<Dvd> filmes = new ArrayList<Dvd>();
private Cliente cliente = null;
private BigDecimal precoTotal = null;

public BigDecimal getPrecoTotal() {


return precoTotal;
}

public void setPrecoTotal(BigDecimal precoTotal) {


this.precoTotal = precoTotal;
}

public Cliente getCliente() {


return cliente;

Fragmental Tecnologia da Informação LTDA – CNPJ: 07.708.661/0001-15 - http://www.fragmental.com.br


}

public void setCliente(Cliente cliente) {


this.cliente = cliente;
}

public Collection<Dvd> getFilmes() {


return filmes;
}

public void setFilmes(Collection<Dvd> filmes) {


this.filmes = filmes;
}
}
O que é essa classe se não uma estrutura de dados? Ela não possui inteligência nenhuma,
poderia ser convertida numa struct C ou num register Pascal sem muitos problemas...
E quem manipula a estrutura? Temos uma classe cujos métodos fazem isso. Este tipo de
classe também é chamado de “classe de lógica” por algumas pessoas, mesmo a Orientação a
Objetos presumindo que você coloque dados e lógica em uma unidade só (os tais objetos!). No
nosso exemplo poderíamos ter:
public class GerenciadorLocadora {
public Aluguel alugarDvd(Cliente cliente, Collection<Dvd> filmes) {
Aluguel novoAluguel = new Aluguel();
novoAluguel.setCliente(cliente);
BigDecimal precoTotal = new BigDecimal("0");
for (Dvd dvd : filmes) {
novoAluguel.getFilmes().add(dvd);
precoTotal.add(dvd.getPreco());
}
novoAluguel.setPrecoTotal(precoTotal);
return novoAluguel;
}
}
E então temos um método que manipula completamente nossa estrutura de dados. Se você
não está propositalmente criando uma aplicação Procedural (mesmo neste caso é importante
ler sobre Programação Procedural e suas boas práticas), deve corrigir alguns problemas.
Neste esquema é possível que um objeto da classe Aluguel seja criado e utilizado sem ter um
cliente . Como verificar o estado deste objeto? Todos os seus objetos vão precisar saber que
Aluguel precisa de Cliente, uma repetição de código sem fim.
Um dos grandes problemas neste exemplo em específico é o preço total do aluguel. Como a
classe não possui qualquer inteligência, vamos ter que sempre confiar que quem a utilizar
atualize o preço corretamente. Imagine quanto prejuízo pode causar um método que adiciona
um DVD e esquece de aumentar o preço, ou vice-versa?

Fragmental Tecnologia da Informação LTDA – CNPJ: 07.708.661/0001-15 - http://www.fragmental.com.br


O que acontece se você precisa mudar sua implementação da coleção de filmes para um Set
mas em vários lugares do seu sistema estão fazendo algo como:
List alugados = (List) aluguel.getFilmes();
Em muitos sistemas pode ser apenas uma questão de usar Find/Replace na IDE, mas para
sistemas grandes isso costuma ser bem mais complicado, com código espalhado em vários
lugares que precisam ser testados novamente após qualquer mudança. O que era uma cosia
simples pode se tornar um processo caro e demorado.

Convertendo Código Procedural em Orientado a Objetos


Podemos converter este código em algo mais OO simplesmente pegando a responsabilidade
que é da classe Aluguel e está espalhada em outros lugares, no caso no nosso
GerenciadorLocadora.
Antes de mais nada, remova todos os getters e setters da classe Aluguel. Nós iremos voltar
com eles conforme formos precisando.
Agora pense um pouco no GerenciadorLocadora. O que este método deveria fazer é apenas
receber uma lista de DVDs para um cliente e devolver uma instância de Aluguel, nada de se
preocupar com preços ou coisa do tipo...
Vamos simplificar:
public class GerenciadorLocadora {
public Aluguel alugarDvd(Cliente cliente, Collection<Dvd> filmes) {
Aluguel novoAluguel = new Aluguel(cliente);
for (Dvd dvd : filmes) {
novoAluguel.adicionar(dvd);
}
return novoAluguel;
}
}
Uhm.. bem melhor. Nós vamos passar o cliente no construtor do objeto porque no nosso
sistema todo aluguel tem um cliente associado sempre (isso é uma invariante da classe),
então ela precisa de um objeto cliente desde o momento de sua criação.
Depois nós apenas adicionamos um a um os DVDs. Poderíamos ter um método de
conveniência que recebesse uma lista com os DVDs e os adicionassem em lote, mas por
enquanto esta bom assim.
Já que esta classe não lida mais com preços, como fica nosso Aluguel?
public class Aluguel {
private Collection<Dvd> filmes = new ArrayList<Dvd>();
private Cliente cliente = null;
public Aluguel(Cliente cliente) {
super();
this.cliente = cliente;
}
public void adicionar(Dvd dvd){
filmes.add(dvd);
}

Fragmental Tecnologia da Informação LTDA – CNPJ: 07.708.661/0001-15 - http://www.fragmental.com.br


public BigDecimal getPrecoTotal(){
BigDecimal precoTotal = new BigDecimal("0");
for (Dvd dvd : filmes) {
precoTotal.add(dvd.getPreco());
}
return precoTotal;
}
public Collection<Dvd> getFilmes(){
return Collections.unmodifiableCollection(filmes);
}
}
Nada muito complexo, mas com alguma inteligência para implementar a responsabilidade que
é da classe. Agora não existe mais aluguel sem cliente, desde o início de sua vida o Aluguel
tem um cliente associado (você pode checar para não receber null).
A coleção de filmes também não é mais exposta. Se alguém precisar listar os filmes nós
utilizamos uma técnica chamada Defensive Copying. O que nós retornamos não é mais a nossa
lsita de filmes mas uma cópia dela que não pode ser sequer modificada. Não teremos
problemas de inconsistência.
O preço agora é calculado de uma maneira dinâmica. Se nossos sistema crescer muito e
calcular o preço toda hora fique muito caro em performance, podemos armazenar o valor já
calculado, mas o importante é que agora nós podemos implementar a classe como quisermos,
sem se preocupar com quem irá usar nossa coleção de filmes e atualizar o preço total.

Conclusão
Na verdade, o problema em um código procedural está antes dele ter sequer ter sido escrito. O
grande problema é pensar de maneira procedural, escrever código é só consequência disso.
Mais que sair por aí olhando código já pronto para identificar comportamento procedural,
devemos nos preocupar em entender melhor o que faz um objeto e como um sistema
construído desta forma diverge de um sistema procedural.
O exemplinho bobo de locadora (um estereótipo de sistema pequeno e simples) representa
código visto em sistemas de todos os tamanhos, feitos por profissionais ou estudantes. Tente
entender a filosofia por trás do encapsulamento.

Referências & Leituras Indicadas


Fantoches: http://fragmental.com.br/wiki/index.php?title=Fantoches
Contratos Nulos: http://fragmental.com.br/wiki/index.php?title=Contratos_Nulos

Sobre o Autor
Phillip Calçado “Shoes” é arquiteto de software com 10 anos de experiência. É membro do
conselho nacional da International Association of Software Architects (IASA), Coordenador do
RioJUG (Grupo de Usuários Java do Rio de Janeiro), do GUJ, articulista da revista Mundo Java e
palestrante nos principais eventos nacionais de desenvolvimento. Mais artigos em
http://www.fragmental.com.br.

Fragmental Tecnologia da Informação LTDA – CNPJ: 07.708.661/0001-15 - http://www.fragmental.com.br


Atribuição-Compartilhamento pela mesma licença 2.5 Brasil
Você pode:
• copiar, distribuir, exibir e executar esta obra
• criar obras derivadas
• fazer uso comercial da obra

Sob as seguintes condições:

Atribuição. Você deve dar crédito ao autor original, da


forma especificada pelo autor ou licenciante.

Compartilhamento pela mesma Licença. Se você alterar,


transformar, ou criar outra obra com base nesta, você
somente poderá distribuir a obra resultante sob uma licença
idêntica a esta.

● Para cada novo uso ou distribuição, você deve deixar


claro para outros os termos da licença desta obra.
● Qualquer uma destas condições podem ser
renunciadas, desde que Você obtenha permissão do
autor.

Qualquer direito de uso legítimo (ou "fair use") concedido por lei, ou qualquer
outro direito protegido pela legislação local, não são em hipótese alguma
afetados pelo disposto acima.
Este é um sumário para leigos da Licença Jurídica (na íntegra).
Termo de exoneração de responsabilidade

Fragmental Tecnologia da Informação LTDA – CNPJ: 07.708.661/0001-15 - http://www.fragmental.com.br

Você também pode gostar