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

[Projeto] Sistema bancário

Tentei aplicar de uma maneira diferente, só uma dúvida que fiquei, seria necessário a ação deposit e withdraw, ter uma classe para si mesmas ? OU poderia deixar apenas o método na classe BankAccount mesmo ?

Main :

public static void main(String[] args) {
        try{
            Person person = new Person("Igor",26,"99999999999");
            BankAccount bankAccount = new BankAccount("25",12356,person);
            BankOperation deposit = new Deposit(1000);
            BankOperation withdraw = new Withdraw(800);
            deposit.execute(bankAccount);
            withdraw.execute(bankAccount);
            System.out.println(bankAccount.getBalance());
        }catch (NoBalanceException | InvalidCpf e){
            System.err.println(e.getMessage());
        }

    }

Person:

 String name;
    int age;
    String cpf;
    BankAccount bankAccount;

    public Person(String name, int age , String cpf) {
        this.name = name;
        this.age = age;
        checkCpf(cpf);
        this.cpf = cpf;
    }

    public void checkCpf(String cpf){
        if(cpf.length() == 11){
            Pattern pattern = Pattern.compile("^\\d+$");
            Matcher matcher = pattern.matcher(cpf);
            if(!matcher.matches()){
                throw new InvalidCpf("Cpf only accept numbers");
            }
        }
        else{
            throw new InvalidCpf("Invalid CPF");
        }

    }

BankAccount :

 private double balance;
    private final String agencia;
    private final long number;
    private Person owner;

    public BankAccount(String agencia, long number, Person person) {
        this.agencia = agencia;
        this.number = number;
        this.owner = person;
    }

    public void deposit(double value){
        this.balance += value;
    }

    public void withdraw(double value){
        this.balance -= value;
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "balance=" + balance +
                ", agencia='" + agencia + '\'' +
                ", number=" + number +
                ", owner=" + owner +
                '}';
    }

    public double getBalance() {
        return balance;
    }

    public String getAgencia() {
        return agencia;
    }

    public long getNumber() {
        return number;
    }

    public Person getOwner() {
        return owner;
    }

BankOperation :

public abstract class BankOperation implements BankAction{
    private double amount;

    public BankOperation(double amount) {
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }
}

Deposit :

public class Deposit extends BankOperation{

    public Deposit(double amount) {
        super(amount);
    }

    @Override
    public void execute(BankAccount bankAccount){
        bankAccount.deposit(super.getAmount());
        System.out.println("Deposit of " + super.getAmount() + " successful");
    }
}

Withdraw :

public class Withdraw extends BankOperation{

    public Withdraw( double amount){
        super(amount);
    }

    @Override
    public void execute(BankAccount bankAccount) {
        if(bankAccount.getBalance() < super.getAmount()){
            throw new NoBalanceException("Balance insufficient");
        }
        bankAccount.withdraw(super.getAmount());
        System.out.println("Withdraw of " + super.getAmount() + " successful");
    }

}

Exceptions :

public class InvalidCpf extends RuntimeException {
    public InvalidCpf(String message) {
        super(message);
    }
}

public class NoBalanceException extends RuntimeException {
    public NoBalanceException(String message) {
        super(message);
    }
}
2 respostas
solução!

Oi, Igor, tudo bem?

Excelente trabalho no seu código! Adorei ver que você tentou uma abordagem diferente e explorou conceitos mais avançados de orientação a objetos.

Respondendo diretamente à sua dúvida: não é estritamente necessário ter classes separadas para as ações de depósito e saque. Ambas as abordagens estão corretas, mas elas servem a propósitos de design diferentes.

Na maioria dos sistemas mais simples e nos exemplos iniciais de Orientação a Objetos, nós deixamos o deposit() e o withdraw() apenas como métodos dentro da própria BankAccount. O código fica mais simples, direto e fácil de ler. A própria conta gerencia seu estado (saldo), o que respeita perfeitamente o princípio do encapsulamento.

O que você fez foi separar o "comportamento" em classes independentes. Na engenharia de software, isso se aproxima muito de Padrões de Projeto como o Command ou o Strategy.

Essa estrutura brilha quando o sistema cresce. Imagine que agora você precise gerar um extrato bancário. Como cada transação é um objeto independente (instância de Deposit ou Withdraw), você poderia facilmente ter uma List<BankOperation> dentro da sua conta para guardar o histórico de tudo que aconteceu!
Se amanhã o banco criar uma operação de "PIX" ou "Pagamento de Boleto", você só cria uma classe nova que herda de BankOperation, sem precisar mexer e "inchar" o código da classe BankAccount (isso é o famoso princípio Open/Closed do SOLID).

O seu código ficou muito bem estruturado e demonstra uma ótima maturidade em POO! Para o desafio atual, deixar apenas os métodos na conta seria o suficiente, mas a sua arquitetura está preparadíssima para escalar caso o sistema cresça.

Bons estudos!

Sucesso

Imagem da comunidade

Entendi, mais para frente vou analisar esses padrões. Muito obrigado Victor