Orientação a Objetos: Conheça os erros mais comuns e como evitá-los

Saiba nesse artigo como o entendimento de alguns conceitos básicos pode aumentar o reuso e facilitar a manutenção do código.

Fique por dentro
Neste artigo serão apresentados alguns dos erros mais comuns realizados por desenvolvedores Java, principalmente por não compreenderem perfeitamente os fundamentos da própria Orientação a Objetos.

Exemplos mostram como identificar trechos de código com alto acoplamento e como isso prejudica a manutenção e a extensão de um sistema OO.

Além disso, os propósitos de conceitos como Encapsulamento, Herança e Polimorfismo, bem como o padrão Modelo-Visão-Controle, são revisitados, mostrando como utilizá-los corretamente para deixar o projeto mais rico e facilitar o reuso de classes.

Quando ouvimos falar em Java como linguagem de programação, a expressão “Orientação a Objetos” logo vem à cabeça. Apesar de ser um dos primeiros temas a estudar quando aprende-se a programar em Java, muitas pessoas o negligenciam achando, por exemplo, que Encapsulamento se reduz a utilizar métodos do tipo getXXX() e setXXX() em suas classes quando, na verdade, estes tipos de métodos devem ser evitados a qualquer custo justamente por ferir este princípio fundamental.

Outros exibem orgulhosos a “árvore genealógica” das classes que compõem o seu sistema, sem saber que o esforço para estender e manter o código funcionando corretamente aumenta proporcionalmente com o tamanho da “árvore”.

Diante deste cenário, este artigo tem como objetivo principal revisitar os conceitos fundamentais da Orientação a Objetos: Encapsulamento, Herança e Polimorfismo.

Ao mesmo tempo, alguns padrões GRASP (General Responsibility Assignment Software Patterns) são introduzidos. Estes padrões, ao contrário dos Padrões de Projeto escritos pela “Gangue dos Quatro”, possuem o objetivo de facilitar o entendimento sobre quais são as responsabilidades de cada classe em um sistema.

Apesar de muitos desenvolvedores considerarem estes padrões mais básicos, sua importância é enorme e não deve ser menosprezada pois, nem mesmo uma abordagem ágil com todas as suas técnicas que preveem suporte a alterações frequentes no código, é capaz de diminuir os impactos negativos de um código mal escrito.

Nota: Durante o desenvolvimento de softwares orientados a objetos, existem alguns problemas que são recorrentes, ou seja, aparecem várias vezes e em diferentes situações, às vezes até “mascarados” como problemas diferentes. Desta forma, há algum tempo, quatro dos grandes nomes da comunidade de orientação a objetos (Erich Gamma, John Vlissides, Ralph Johnson e Richard Helm) perceberam esse padrão e começaram a catalogar as soluções utilizadas para resolver estes problemas, dando nomes a elas e descrevendo como e quando utilizá-las.

Posteriormente, estas soluções foram compartilhadas através do livro “Padrões de Projeto: soluções reutilizáveis de softwares orientados a objetos” e seus autores passaram a ser conhecidos como a “Gangue dos Quatro”. O livro é uma referência até hoje para aqueles que querem se aprofundar no estudo da orientação a objetos.

Como exemplo, considere as Listagens 1, 2 e 3, onde são exibidas as classes de um sistema bancário simples que permite a criação de agências. O código foi propositalmente escrito com a classe que representa o domínio (AgenciaBancaria) contendo somente métodos getXXX() e setXXX(), funcionando como um recipiente de dados.

O padrão arquitetural Modelo-Visão-Controle (outro conceito mal compreendido por muitos desenvolvedores) foi utilizado como forma de separar as responsabilidades envolvidas em cada classe. A Figura 1 mostra o diagrama de classes deste sistema.

Listagem 1. Classe que representa o domínio do problema no sistema bancário.


public class AgenciaBancaria {
   private String codigo;
   private List<ContaBancaria> contas = new LinkedList<>();
   public List<ContaBancaria> getContas() {
         return contas;
   }
   public void setContas(List<ContaBancaria> contas) {
         this.contas = contas;
   }
   public String getCodigo() {
         return codigo;
   }
   public void setCodigo(String codigo) {
         this.codigo = codigo;
   }
}
    

Listagem 2. Classe que representa a lógica de negócio no sistema bancário.


public class ControladorAgencia {
   private List<AgenciaBancaria> agencias = new LinkedList<>();
   public void adicionaAgencia(AgenciaBancaria agencia) {
         agencias.add(agencia);
   }
   public AgenciaBancaria buscarAgencia(String codigo) {
                for (AgenciaBancaria agenciaBancaria : agencias) {
                if(agenciaBancaria.getCodigo().equals(codigo)){
                       return agenciaBancaria;
                }
         }
         return null;
   }
}
    

Listagem 3. Classe que representa a interface com o usuário do sistema bancário.


public class VistaAgencia {
   private int codigoAgencia = 1; 
   private ControladorAgencia controlador = new ControladorAgencia();
   public void exibir(){
         Scanner scan = new Scanner (System.in);
         String opcao = "";
         while(opcao != null){
                System.out.println ("Digite : ");
                System.out.println("[1] Para criar nova agencia");
                System.out.println("[2] Para buscar uma agencia");
                System.out.println("[3] Para sair.");
                opcao = scan.nextLine();
                if(opcao.equals("1")){
                       String codigo = String.valueOf(codigoAgencia);
                       codigoAgencia = codigoAgencia + 1;
                       AgenciaBancaria agencia = new AgenciaBancaria();
                       agencia.setCodigo(codigo);
                       controlador.adicionaAgencia(agencia);
                       System.out.println(“Agencia criada com sucesso. Código: “+codigo”);
                }
                if(opcao.equals("2")){
                       System.out.println("Digite o codigo da agencia:");
                       String codigo = scan.nextLine();
                       AgenciaBancaria agencia = controlador.buscarAgencia(codigo);
                       System.out.println("Codigo da agencia: "+agencia.getCodigo());
                       System.out.println("Numero de contas: "+agencia.getContas().size());
                }
                if(opcao.equals("3")){
                       opcao = null;
                }
         }
         scan.close();  
   }
}
    "

[...] continue lendo...

Artigos relacionados