Saga do programador

12Dec/096

Analisando o codigo escrito anteriormente.

Terminei meu post anterior com a pergunta: "Este código está bom? Porque?"

Para analizar um código, assim como qualquer outra coisa, nós precisamos de parâmetros. Precisamos nos basear em algo que saibamos que seja bom, para assim podermos determinar se outra coisa é tão boa quanto, melhor, ou até pior.

Com código não é diferente. Então antes de respondermos a pergunta feita no inicio deste texto, precisamos definir o que é um código bom, ou melhor, que caracteristicas deve ter um codigo para ser considerado bom. Vamos agora recorrer a alguns principios OO para nos municiar de paramêtros para assim julgarmos o codigo em questão

Robert Martin, o uncle Bob, escreveu a muito tempo sobre os principios OO num documento chamado: PrinciplesOfOod. Dos principios OO descritos neste artigo, pelo menos 5 ficaram bastante famosos, e são conhecidos pela sigla SOLID, são eles:

Single Responsibility Principle (SRP) - A classe deve ter uma única responsabilidade, uma única razão de existir.

Open Closed Principle (OCP) - A classe deve ser aberta para extensão (sublcasses e sobrescrita de metodos) e fechada para modifiação *

Liskov Substitution Principle (LSP) - Resumidamente ele serve para nos aletar para heranças sem sentido.

Interface Segregation Principle (ISP) - Defende que uma classe deve depender apenas dos métodos que usa de uma outra classe. Interfaces são um mecanismo para isso.

Dependency Inversion Principle (ISP) - Defende que componentes maiores devem depender não de componentes menores, mas sim de uma abstração deles.

*Pode ser discutido, principalmente se você estiver trabalhando em um modelo de dominio incremental, ou seja, você vai descobrindo as necessidades de suas classes durante o desenvolvimento de software. Neste cenário o principio OCP pode ser radical demais. Lembre-se é preciso ter bom senso.

Dos principios descritos por Robert Martin, ficaremos apenas com o SRP. Sabendo agora que uma classe deve possuir apenas uma úncia responsabilidade. Quantas responsabilidades podemos identificar na classe Principal do post anterior?

Podemos identificar facilmente 3 responsabilidades. São elas:

1 - Controla a execução da aplicação.

2 - Cadastra um novo DVD

3 - Lista todos os DVD's cadastrados

Agora ficou facil ver que a classe Principal está ferindo o SRP. A resposabilidade desta classe deveria ser apenas: Controlar a execução da aplicação. Precisamos retirar da classe Principal as demais responsabilidades. Como faremos isso?

A melhor solução é remover todo o código "extra" da classe Principal. Mas o grande problema, é que sem esse codigo nossa aplicação vai parar de funcionar! Este código não pode simplesmente desaparecer. O que nós precisamos fazer e leva-lo para outro lugar. E como estamos programando segundo o paradigma de Orientação a Objetos, vamos precisar de novas classes para cada uma das responsabilidades descritas acima.

Teriamos as seguintes classes com as seguintes responsabilidades:

Classe: Principal

Responsabilidade: Controlar a execucao da aplicação

Classe: CadastrarDvd

Responsabilidade: Cuidar da lógica de inclusao de um dvd

Classe: ListarTodosDvds

Responsabilidade: Cuidar da lógica de exibicao dos dvd's

Após estas alterações vamos perceber que a classe Principal ficou bem melhor.

Mas será que isso foi suficiente? Apenas esta alteração terá salvado a vida de nossa pequena aplicação?

Tente aplicar você mesmo o SRP em nossas novas classes e comente a respeito. No proximo post continuamos nossa saga.

Abraços.

Sergio Azevedo Junior

Confira abaixo como ficaram nossas classes:

Principal

public class Principal {
  public static void main(String[] args) throws IOException {
    Scanner scan = new Scanner(System.in);
    int opcao = 0;
    do {
      System.out.println("--------------- Controle de Dvds e Cds ---------------");
      System.out.println("   1 - Cadastrar Novo Dvd ");
      System.out.println("   2 - Listar Dvd's ");
      System.out.println("   3 - Terminar ");
      System.out.println("------------------------------------------------------");
      System.out.println(" Escolha uma opção:--> ");
 
      opcao = scan.nextInt();
      switch (opcao) {
      case 1: {
        new CadastraDvd().executa();
        break;
      }
      case 2: {
        new ListaTodosDvds().executa();
        break;
      }
      }
    } while (opcao < 3);
  }
}

CadastraDvds

public class CadastraDvd {
 
  public void executa() throws IOException {
    PrintStream ps = null;
    File file = new File("Dvds.txt");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    try {
      ps = new PrintStream(file);
 
      Dvd dvd = new Dvd();
      System.out.println("Titulo.: ");
      dvd.setTitulo(br.readLine());
      System.out.println("Sinopse: ");
      dvd.setSinopse(br.readLine());
      System.out.println("Genero.: ");
      dvd.setGenero(br.readLine());
      System.out.println("Ano....: ");
      dvd.setAno(br.readLine());
      System.out.println("Duracao: ");
      dvd.setDuracao(br.readLine());
 
      ps.println(dvd.getTitulo());
      ps.println(dvd.getSinopse());
      ps.println(dvd.getGenero());
      ps.println(dvd.getAno());
      ps.println(dvd.getDuracao());
    } finally {
      br.close();
      if (ps != null)
        ps.close();
    }
  }
}

ListaTodosDvds

public class ListaTodosDvds {
  public void executa() throws FileNotFoundException {
    System.out.println("------------- Lista de Dvd's -------------");
    Scanner reader = new Scanner(new File("Dvds.txt"));
    while (reader.hasNext()) {
      System.out.println(reader.nextLine());
    }
    reader.close();
  }
}

Sobre Sergio Azevedo Junior

Desenvolvedor apaixonado e blogueiro.
Comentários (6) Trackbacks (0)
  1. Gostei bastante das referências.
    Muito show!
    []´s

  2. No caso do CRUD completo de DVD, teriamos 4 classes para fazer essas operações?

  3. Olá Gregory, como você perecebeu se seguirmos a risca e sem pensar mais em nada a ideia proposta por este post teriamos sim uma classe para cada operação do CRUD. Isso nao parece muito legal neh? A questao é exatamente essa como melhorar isso? Como evitar de criar 4 classes diferentes para fazer CRUD sem misturar responsabilidades?

    Abraços

  4. Criar uma classe ManterDVD? ;]

  5. Criar a classe ManterDVD seria uma opção sim. Em geral quando o pessoal faz isso costuma dar um nome mais bonito, um nome que expressa melhor o propósito do objeto. Na veradade uma classe deste tipo, acaba tendo como responsabiliade “esconder” toda lógica e complexidade a cerca do “acesso à dados”. Tipo quem usar a sua classe ManterDVD e pedir para recuperar o DVD de id 10, nao quer saber se este DVD está no banco de dados, num arquivo texto, num XML, ou se isso está vindo de algum lugar da internet. Tudo o que o utilizador da classe ManterDVD vai querer é que o objeto DVD de id 10 seja recuperado para ele. Assim sua classe ManterDVD isolaria a lógica de acesso a dados, e poderia se chamar Objeto de Acesso a Dados DVD, só que o pessoal costuma usar o nome em ingles (Data Access Object), e abreviado assim ficamos com DvdDAO.
    Referência:
    http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

  6. Mesmo colocando essas quatro operações, a classe fica com uma única responsabilidade: persistir dados com o banco.


Deixar um comentário


Trackbacks estão desabilitados