1
resposta

Dúvida Chain of Responsibility

Quando comecei a passar o proximo item da corrente pelo construtor no exemplo que foi dado no vídeo da aula comecou a dar erro pois não tinha o que passar pra classe SemDesconto, já que esse é o final da corrente, tentei passar null para a última classe antes da SemDesconto pra não precisar dela, mas mesmo assim não consegui fazer funcionar.

Segue códigos :

Ultima classe antes da SemDesconto :

<?php 
    require_once "Orcamento.php";
    require_once "Desconto.php";

    class DescontoPorVendaCasada implements IDesconto{
        private $proximo;

        public function __construct(IDesconto $proximo){
            $this->proximo = $proximo;
        }

        public function desconto(Orcamento $orcamento){
            if ($this->existe("LAPIS",$orcamento) && $this->existe("CANETA",$orcamento)){
                return $orcamento->getValor() * 0.05;
            } else {
                if (!is_null($proximo)) 
                    return $proximo->desconto($orcamento);
            }
        }

        private function existe($nomeItem, Orcamento $orcamento){
            foreach ($orcamento->getItens() as $item) {
                if ($item->getNome() == $nomeItem) return true;
            }

            return false;
        }
    }

Classe CalculadoraDeDesconto:

<?php 
    require_once "Desconto.php";
    require_once "Desconto5Itens.php";
    require_once "Desconto500Reais.php";
    require_once "DescontoPorVendaCasada.php";
    require_once "SemDesconto.php";
    require_once "Orcamento.php";

    class CalculadoraDeDesconto{
        private $desconto5Itens;
        private $desconto500Reais;
        private $descontoPorVendaCasada;
        private $semDesconto;

        public function calcular(Orcamento $orcamento){

            // $semDesconto = new SemDesconto(null);
            $descontoPorVendaCasada = new DescontoPorVendaCasada(null);
            $desconto500Reais = new Desconto500Reais($descontoPorVendaCasada);
            $desconto5Itens = new Desconto5Itens($desconto500Reais);


            $desconto5Itens->setProximo($desconto500Reais);
            $desconto500Reais->setProximo($descontoPorVendaCasada);
            $descontoPorVendaCasada->setProximo($semDesconto);

            return $desconto5Itens->desconto($orcamento);
        }
    }

Interface do Desconto :

<?php 
    require_once "Orcamento.php";

    interface IDesconto{
        public function desconto(Orcamento $orcamento);
        public function __construct(IDesconto $proximo);
    }
1 resposta

Olá, Caue.

É muito incomum uma interface definir o construtor. Quando se precisa de um construtor com uma assinatura específica, é muito mais comum utilizar uma classe abstrata. Eu sinceramente nunca tinha visto uma interface definir construtor.

Minha sugestão é fazer o seguinte: - Remover o construtor da Interface. - Na classe SemDesconto, não ter o construtor, e o método desconto retorna 0 (nenhum desconto). - No construtor de DescontoPorVendaCasada você passa a instância de SemDesconto.

interface Desconto
{
    public function desconto(Orcamento $orcamento);
}

public class SemDesconto implements Desconto
{
    public function desconto(Orcamento $orcamento)
    {
        return 0;
    }
}

class CalculadoraDeDesconto
{
    private $desconto5Itens;
    private $desconto500Reais;
    private $descontoPorVendaCasada;
    private $semDesconto;

    public function calcular(Orcamento $orcamento)
    {

        $semDesconto = new SemDesconto();
        $descontoPorVendaCasada = new DescontoPorVendaCasada($semDesconto );
        $desconto500Reais = new Desconto500Reais($descontoPorVendaCasada);
        $desconto5Itens = new Desconto5Itens($desconto500Reais);

        $desconto5Itens->setProximo($desconto500Reais);
        $desconto500Reais->setProximo($descontoPorVendaCasada);
        $descontoPorVendaCasada->setProximo($semDesconto);

        return $desconto5Itens->desconto($orcamento);
    }
}

Vê se isso te atende e dá um retorno.

Abraços e bons estudos.