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

Exercício 5 Aula 6 Curso Design Patterns I - Fiz diferente mas acho que ficou bem legal.

Na resposta do exercício o instrutor cria os métodos para depositar e sacar nas classes de Estado. Eu, por outro lado, criei os métodos de sacar e depositar na classe conta e estabeleci as regras de depósito (desconto de percentual) e saque (autorização de saque) nas classes de estado. Ficou com um pouquinho a mais de código, mas acredito que as responsabilidades de cada classe e método estejam bem atribuídas e legíveis. Pergunto-lhes, há algo errado com a solução que adotei (podendo me causar algum transtorno no futuro)?

<?php

class Conta
{
    private $nome;
    private $saldo;
    private $estado;

    public function __construct($nome, $saldo)
    {
        $this->nome = $nome;
        $this->saldo = $saldo;
        $this->setEstado();
    }

    public function getNome()
    {
        return $this->nome;
    }

    public function getSaldo()
    {
        return $this->saldo;
    }

    public function deposita($valor)
    {
        $valor = $this->estado->descontaDeposito($valor);
        $this->saldo += $valor;
        $this->setEstado();
    }

    public function saca($valor)
    {
        if($this->estado->autorizaSaque()) {
            $this->saldo -= $valor;
        } else {
            throw new Exception ("Não é possível realizar o saque de conta com estado negativo");
        }

        $this->setEstado();
    }

    private function setEstado()
    {
        if($this->saldo > 0) {
            $this->estado = new EstadoPositivo;
        } else {
            $this->estado = new EstadoNegativo;
        }
    }
}
<?php

require_once 'EstadoConta.php';

class EstadoPositivo implements EstadoConta
{
    public function descontaDeposito($valor)
    {
        return $valor - $valor * 0.02;
    }

    public function autorizaSaque()
    {
        return true;
    }
}
<?php

require_once 'EstadoConta.php';

class EstadoNegativo implements EstadoConta
{
    public function descontaDeposito($valor)
    {
        return $valor - $valor * 0.05;
    }

    public function autorizaSaque()
    {
        return false;
    }
}
2 respostas
solução!

Oi Natan, tudo bom?

Gostei do nome que você deu pros métodos responsáveis pela regra de negocio do saque em relação ao estado. Ficou bem semantico.

Acho que faltou manter a atribuição do saldo dentro do estado. Isso porque, na implementação sem, a gente é obrigado a lembrar de atribuir isso com o retorno:

public function deposita($valor)
    {
        $valor = $this->estado->descontaDeposito($valor);
    //aqui a gente tem que lembrar de atribuir
        $this->saldo += $valor;
        $this->setEstado();
    }

O ideal seria que o estado, ao descontar o deposito, já atualizasse a conta. Tanto porque, esse método não deve ser usado em nada que não seja uma conta.

Recebendo a conta e atualizando direto, a gente amarra esse comportamento a conta:

public function descontaDeposito(Conta $conta, $valor) {
        $conta->saldo += $valor * 0.95;
        if($conta->saldo > 0) $conta->estado = new Positivo();
      }

Outro detalhe, o método set costuma receber sempre um parametro. Ele é utilizado literalmente para atribuir o valor. No seu caso, o setter está calculando o valor dependendo do estado da conta, um nome melhor pra ele seria algo como deduzEstado ou calculaEstado, que é realmente o que o método faz.

Muito legal sua solução =)

Mais legal ainda você ter compartilhado ela com a gente, pra discutir!

Abraço.

Obrigado pelas observações André!