Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Projeto Calculadora

Bom dia galera, estou fazendo uma calculadora apenas para exercitar LP e gostaria de uma opinião sobre como melhorar este projeto.

Tenho esta topologia e gostaria de diminuir a responsabilidade da minha classe CalculadoraPrincipal. Eu criei uma interface chamada Operacao que tem apenas um método calcula, toda classe que desejar realizar uma operação matemática deve assinar este contrato e saber calcular os valor recebidos como parâmetro. A classe CalculadoraPrincipal cria o fluxo de entrada/saída de dados e chama o método calcula dependendo da escolha do usuário.

Um outro problema é que meu código possui muitos Ifs e sempre que precisar adicionar uma nova operação como por exemplo raiz quadrada, vou precisar adicionar um novo If.

Se alguém souber de algum Design Pattern apropriado para este problema, ou alguma outra ideia, ajudaria muito!

package br.com.jorge.calculadora;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Scanner;

public class CalculadoraPrincipal {

    public static void main(String[] args) throws IOException, InterruptedException {

        Scanner scan = new Scanner(System.in);
        boolean continua = true;
        FileWriter fw = new FileWriter("numeroscalculados.txt");

        while (continua) {

            System.out.println("1 - Soma \n2 - Subtração \n3 - Multiplicação \n4 - Divisão.");
            System.out.println("Qual operação deseja efetuar?");
            int operacao = scan.nextInt();
            System.out.println("Digite o primeiro valor: ");
            BigDecimal valor1 = scan.nextBigDecimal();
            System.out.println("Digite o segundo valor: ");
            BigDecimal valor2 = scan.nextBigDecimal();

            if (operacao == 1) {
                Operacao soma = new Soma();
                System.out.println(soma.calcula(valor1, valor2));
                fw.write("Soma de " + valor1 + " + " + valor2 + "\n");
            }

            if (operacao == 2) {
                Operacao subtracao = new Subtracao();
                System.out.println(subtracao.calcula(valor1, valor2));
                fw.write("Subtração de " + valor1 + " - " + valor2 + "\n");
            }

            if (operacao == 3) {
                Operacao multiplica = new Multiplica();
                System.out.println(multiplica.calcula(valor1, valor2));
                fw.write("Multiplicação de " + valor1 + " * " + valor2 + "\n");
            }

            if (operacao == 4) {
                Operacao divisao = new Divide();
                System.out.println(divisao.calcula(valor1, valor2));
                fw.write("Divisão de " + valor1 + " / " + valor2 + "\n");
            }

            System.out.println("Deseja continuar a operação?  \n1 - Sim \n2 - Não");
            int reiniciar = scan.nextInt();
            if (reiniciar == 2) {
                continua = false;
                scan.close();
                fw.close();
            }

            System.out.println("Obrigado por utilizar a calculadora!");

        }

    }

}
package br.com.jorge.calculadora;

import java.math.BigDecimal;

public interface Operacao {

    public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2);

}
package br.com.jorge.calculadora;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Divide implements Operacao {

    public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) {
        return BigDecimal.valueOf(valor1.doubleValue() / valor2.doubleValue()).setScale(2, RoundingMode.HALF_UP);
    }

}
package br.com.jorge.calculadora;

import java.math.BigDecimal;

public class Multiplica implements Operacao {

    public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) {
         return valor1.multiply(valor2);
    }

}
package br.com.jorge.calculadora;

import java.math.BigDecimal;

public class Soma implements Operacao {

    public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) {
        return valor1.add(valor2);
    }

}
package br.com.jorge.calculadora;

import java.math.BigDecimal;

public class Subtracao implements Operacao {

    public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) {
        return valor1.subtract(valor2);
    }

}
6 respostas

Olá Jorge, tudo bem?

Você poderia me mandar o seu projeto? Pode colocar-lo no drive, dropbox, GitHub, etc. Só para mim, editar o seu código e te mostrar uma forma simples de resolver esses ifs.

Boa noite Fábio, tudo ótimo e com você?

Veja se consegue acessar meu repo no github:

https://github.com/queirozjorge/calculadora-java

Valeu pela ajuda! :D

To quebrando a cabeça aqui, mas tô conseguindo kkkk

solução!

Bom, acabei de finalizar aqui. E essas foram as alterações:

  1. Apaguei todas as classes relacionadas a operações.
  2. Utilizei o padrão Strategy bem simples para resolver os problemas dos ifs, utilizando Enum.

ㅤㅤㅤㅤ

Seu código ficou assim:

O Enum:

package br.com.jorge.calculadora;

import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;

public enum CalculosEnuns implements Operacao {

    SOMA {
        public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) throws IOException {
            FileWriter fw = new FileWriter("numeroscalculados.txt");
            fw.write("Soma de " + valor1 + " + " + valor2 + "\n");
            fw.close();

            return valor1.add(valor2);
        }
    },

    SUBTRACAO {
        public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) throws IOException {
            FileWriter fw = new FileWriter("numeroscalculados.txt");
            fw.write("Subtração de " + valor1 + " - " + valor2 + "\n");
            fw.close();

            return valor1.subtract(valor2);
        }
    },

    MULTIPLICACAO {
        public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) throws IOException {
            FileWriter fw = new FileWriter("numeroscalculados.txt");
            fw.write("Multiplicação de " + valor1 + " * " + valor2 + "\n");
            fw.close();

            return valor1.multiply(valor2);
        }
    },

    DIVISAO {
        public BigDecimal calcula(BigDecimal valor1, BigDecimal valor2) throws IOException {
            FileWriter fw = new FileWriter("numeroscalculados.txt");
            fw.write("Divisão de " + valor1 + " / " + valor2 + "\n");
            fw.close();

            return valor1.divide(valor2);
        }
    };

}

Aqui no CalculosEnuns eu implementei a interface Operacao que faz com que cada enum tivesse o mesmo método. E assim eu não precissaria ficar fazendo varios ifs (vai ficar explicito na proxima explicação).

Obs: implementei a função de escrita no método tbm, eu só não soube como não ficar copiando ele para cara enum.

ㅤㅤ

A classe de execução:

package br.com.jorge.calculadora;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Scanner;

public class CalculadoraPrincipal {

    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        boolean continua = true;

        while (continua) {

            System.out.println("Soma | Subtração | Multiplicação | Divisão. \nObs: Não digite com acentuações.");
            System.out.println("Qual operação deseja efetuar?");
            String operacao = scan.next();

            System.out.println("Digite o primeiro valor: ");
            BigDecimal valor1 = scan.nextBigDecimal();

            System.out.println("Digite o segundo valor: ");
            BigDecimal valor2 = scan.nextBigDecimal();

            try{
                CalculosEnuns calculo = CalculosEnuns.valueOf(operacao.toUpperCase());
                System.out.println(calculo.calcula(valor1, valor2));
            } catch (Exception exception) {
                System.out.println("Exception " + exception.getMessage());
                System.out.println("Não existe o Enum: " + operacao.toUpperCase());
            } finally {
                System.out.println("Deseja continuar a operação?  \n1 - Sim `, `, poispois\n2 - Não");
                int reiniciar = scan.nextInt();
                if (reiniciar == 2) {
                    continua = false;
                    scan.close();
                }
            }

        }

        System.out.println("Obrigado por utilizar a calculadora!");

    }

}

Aqui foi onde eu implementei o Strategy. Na variável cálculo eu criei um Enum a partir da String operacao utilizando o valueOf que transforma um String em um Enum e também utilizei o método toUpperCase() para deixar a String em maiuscula como o nome do Enum. Para assim funcionar o padrão Strategy. Além disso, utilizei um try_catch com o finally pois se a pessoa digitar o nome errado do Enum não irá parar o programa.

ㅤㅤ

Conclusão: Assim você não vai precisar ficar criando classes diferentes com os mesmos métodos, basta usar um Enum e pronto!

Assim o seu código fica mais fácil de dar manutenção e de ser entendido. Sem contar que acabos com o ctrl+c e ctrl+v (tirando a parte da escrita de arquivo kkk).

ㅤㅤ

Referencia:

https://www.alura.com.br/artigos/reduzindo-de-n-ifs-para-nenhum-com-strategy-em-java

ㅤㅤ

Espero ter te ajudado, qualquer dúvida pode me chamar novamente :)

Projeto disponivel aqui!

Bom dia Fábio!

Gostei da ideia, a resolução do problema ficou ótima, realmente resolveu o problema kk... Eu tentei aplicar o strategy mas não consegui. Ontem a noite estava pensando em utilizar uma lista com as referências dos objetos operações, passar um foreach por ela comparando com instanceof relacionado a entrada do usuário. Vou tentar essa outra forma e arrumar a parte da escrita de arquivo também kk.

Valeu pela ajuda!

Boa tarde Jorge!

Obrigado kkk, eu tbm demorei muito tempo para pensar em uma possível solução, até que lembrei do Strategy e fui pesquisar sobre.

Em questão de usar uma lista não seria ruim, você poderia criar os objetos e os adicioná-los na lista, e utilizar o foreach para percorrer e pegar a posição do objeto de acordo com a escolha do usuário e assim você poderia chamar o método. Porém você teria que ficar criando objetos desnecessário as vezes, já que você acabaria usando apenas um deles. Mas vale apena tentar :).

Boa sorte com a escrita de arquivos kkkk.