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

Padrão Chain of Responsability - Aula 2 - Não sei porque meu modelo não funciona.

Olá Pessoal, boa noite! Estava praticando o padrão Chain of Responsability e tentei implementar ele em um exercício do capítulo, as classes seguem abaixo: Esta é a minha interface com as classes da cadeia, cada uma com sua lógica de negócio e setter para o próximo retorno:

interface ContaBancaria {
    function retornaFormato(Conta $conta, Requisicao $requisicao);
    function setProximo(ContaBancaria $conta);
}
class ContaPorPorcetagem implements ContaBancaria {
   private $proximoFormato;

   function retornaFormato(Conta $conta, Requisicao $requisicao) {
       if ($requisicao->getCdRequisicao() == 1) {
           return "conta%titular%{$conta->getTitular()}%saldo%{$conta->getSaldo()}";
       } else {
           $this->proximoFormato->retornaFormato($conta, $requisicao);
       }
    }

    function setProximo(ContaBancaria $conta) {
        $this->proximoFormato = $conta;
    }
}
class ContaPorVirgula implements ContaBancaria {
    private $proximoFormato;

    function retornaFormato(Conta $conta, Requisicao $requisicao) {
       if ($requisicao->getCdRequisicao() == 3) {
           return "conta;tutular;{$conta->getTitular()};saldo;{$conta->getSaldo()}";
       } else {
           $this->proximoFormato->retornaFormato($conta, $requisicao);
       }
    }

    function setProximo(ContaBancaria $conta) {
        $this->proximoFormato = $conta;
    }
}
class ContaPorXML implements ContaBancaria {
   private $proximoFormato;

   function retornaFormato(Conta $conta, Requisicao $requisicao) {
       if ($requisicao->getCdRequisicao() == 2) {
           return "<conta>"
                . "<titular>{$conta->getTitular()}</titular>"
                . "<saldo>{$conta->getSaldo()}</saldo>"
           . "</conta>";
       } else {
           $this->proximoFormato->retornaFormato($conta, $requisicao);
       }
    }

    function setProximo(ContaBancaria $conta) {
        $this->proximoFormato = $conta;
    }
}

Logo após eu faço o instanciamento dos objetos e monto a cadeia em uma classe específica clamada CadeiaDeRetorno:

class CadeiaDeRetorno {

    function procuraRetorno(Conta $conta, Requisicao $requisicao) {
        $contaPorcentagem = new ContaPorPorcetagem();
        $contaXML = new ContaPorXML();
        $contaVirgula = new ContaPorVirgula();
        $semFormato = new semFormato();


        $contaPorcentagem->setProximo($contaXML);
        $contaXML->setProximo($contaVirgula);
        $contaVirgula->setProximo($semFormato);

        $retornoFormato = $contaPorcentagem->retornaFormato($conta, $requisicao);
        return $retornoFormato;
    }
}

E depois de tudo isso eu crio duas classes, conta e requisição pra delimitar o tipo do retorno e os dados da conta:

class Conta {
    private $titular;
    private $saldo;

    function __construct($titular, $saldo) {
        $this->saldo = $saldo;
        $this->titular = $titular;
    }

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

    function getTitular() {
        return $this->titular;
    }
}

class Requisicao {
    private $tipoRequisicao;
    private $cdRequisicao;

    function __construct($tipoRequisicao, $cdRequisicao) {
        $this->tipoRequisicao = $tipoRequisicao;
        $this->cdRequisicao = $cdRequisicao;
    }

    function getTipoRequisicao() {
        return $this->tipoRequisicao;
    }

    function getCdRequisicao() {
        return $this->cdRequisicao;
    }
}

E logo depois no index eu instancio os objetos conta, requisição e a cadeia a ser percorrida e percorro a primeira classe:

    $requisicaoXML = new Requisicao("RequisicaoXML", 2);
    $requisicaoVirgula = new Requisicao("Requisição por Virgula", 3);
    $requisicaoPorcentagem = new Requisicao("Requisição por porcentagem", 1);
    $conta = new Conta("Luiz Eduardo Amorim", 530);

    $retornoRequisicao = new CadeiaDeRetorno();
?>

<h1>O formato desejado é:</h1>

<h2><?= $retornoRequisicao->procuraRetorno($conta, $requisicaoPorcentagem); ?></h2>

Sabendo que eu não obtive nenhum erro de execução, imports nem nada do tipo, minhas classes obedecem a interface porém a cadeia não se auto-percorre. Quando eu executo o primeiro item da cadeia caso o retorno não seja o do primeiro if ela não direciona para a próxima classe. Já não sei mais o que testar pra fazer funcionar porque aos meus olhos tudo está certo.

Grato pela ajuda!

2 respostas
solução!

Oi Luiz, tudo bem?

Não testei o seu código (e também não manjo muito de PHP :p) mas vou tentar ajudar:

Observe seus blocos else, como por exemplo, da classe ContaPorPorcetagem:

else {
  $this->proximoFormato->retornaFormato($conta, $requisicao)
}

Quando a chamada ao método retornaFormato retonar, o que vai acontecer? Ele vai sair do else e continuar executando o código até acabar o método.

O que queremos é retornar o resultado dessa execução pra para quem chamou o método do primeiro item da sua cadeia. E pra será necessário colocar um return:

else {
  return $this->proximoFormato->retornaFormato($conta, $requisicao)
}

Abraços!

Obrigado! Ajudou muito!