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

Dependency Inversion Principle

Uma coisa que sempre que uso Solid me causa certa duvida... Quando implementamos o Dependency Inversion Principle, as vezes temos códigos iguais ao do curso, um metodo de uma classe, que simplesmente espera uma Abstração, tem como a implementação desse metodo uma simples chamada de outro método. Por exemplo:

class Assistidor {
    public function assistir(Video $video) {
        $video->assistir();
    }
}

$assistidor = new Assistidor();
$assistidor->assistir(new YoutubeVideos());

Por que continuar com esse código? Muitas vezes criamos uma classe só pra fazer isso, quando seria muito mais rápido e menos verboso, instanciar e chamar o método direto pelo objeto. Por exemplo:

$youtubeVideos = new YoutubeVideos();
$youtubeVideos->assistir();

O único motivo real para isso que consigo pensar, é na questão de coesão em relação ao mundo real, como falado no Curso do botão de play de uma TV. A pessoa não conhece como o play é feito, mas sabe que por ele pode ser feito. Mas será que nesses casos, tao simples, se faz necessário essa nova classe "verbosando" mais o código, só pra isso?

5 respostas

Para códigos pequenos, as abstrações não fazem sentido, pois só tornam o código mais complexo sem necessidade.

O mais importante de abstrações e patterns é saber quando não usá-los. O exemplo que você mostrou indica isso: se a única possibilidade é assistir vídeos do YouTube, pra que encapsular isso numa outra classe e tudo o mais? É muito mais simples chamar a classe diretamente.

Porém, caso tenhamos outras coisas a serem assistidas, faz total sentido essa abstração inicial.

Obrigado pela resposta.

Supondo que tenhamos outras coisas a serem assistidas, não cairíamos na mesma idéia? Exemplo:

$assistidor = new Assistidor();
$assistidor->assistir(new YoutubeVideos());
$assistidor->assistir(new VimeoVideos());
$assistidor->assistir(new AluraVideos());

Mesmo tendo outras opções, ainda não seria mais simples chama-las direto?

Partindo do principio que criaríamos a classe assistidor somente pra isso (chamar o método assistir do objeto passado).

Caso o método assistidor estivesse encapsulando alguma lógica comum a todos os videos, além de simplesmente chamar o método asssitir do objeto passado, ai entendo que de fato seja melhor dessa forma.

Essa abstração nesse caso, se de fato faz sentido, mesmo que seja apenas chamado um único método do objeto passado, faz sentido somente por semantica do mundo real?

Com semantica do mundo real quero dizer, uma "interface" de acesso a forma de assistir, como por exemplo um botao play no mundo real, e no código, uma classe que espera o video e da o play.

Quando fazemos:

$assistidor->assistir(new YoutubeVideos());

Estamos separando as responsabilidades entre um gerenciador de vídeos (o assistidor) e a regra de como pegar um vídeo num provedor específico (o YoutubeVideos)

Mesmo tendo outras opções, ainda não seria mais simples chama-las direto?

Aqui, precisamos responder a seguinte pergunta: "O provedor precisa saber como reproduzir um vídeo (ou tem uma regra específica de reprodução do vídeo)?"

Se cada provedor precisar conhecer as regras de reprodução, então o melhor é chamar direto e usar outras soluções.

No entanto, nesse exemplo acredito que o provedor não precisa conhecer como reproduzir um vídeo. Logo, encapsulamos a regra de reprodução numa classe (o assistidor) e trocamos somente o provedor (YoutubeVideos, VimeoVideos, AluraVideos)

Essa abstração nesse caso, se de fato faz sentido, mesmo que seja apenas chamado um único método do objeto passado, faz sentido somente por semantica do mundo real?

Com semantica do mundo real quero dizer, uma "interface" de acesso a forma de assistir, como por exemplo um botao play no mundo real, e no código, uma classe que espera o video e da o play.

Aqui não estamos considerando o mundo real (embora, por uma coincidência, tenha ficado parecido).

Quando separamos as responsabilidades e programamos voltados à interface, ganhamos algumas coisas:

  • Maleabilidade no código: podemos trocar (ou criar) novos provedores. Bastando que eles implementem o método assistir, o Assistidor vai funcionar normalmente.
  • Podemos rodar o Assistidor num ambiente isolado de testes e passar um provedor fake, para garantir que somente o Assistidor será testado.
  • Os detalhes de um assistidor ficam encapsulados, de forma que o programador não precisa conhecê-los ao estender a outros provedores.

Obrigado pela resposta.

Um detalhe, você disse:

Os detalhes de um assistidor ficam encapsulados , de forma que o programador não precisa conhecê-los ao estender a outros provedores..

Essa é exatamente a questão onde eu queria chegar, nesse assistidor em questão, não existem "detalhes", só estou chamando um método do próprio objeto passado. Nesse caso, faz sentido a abstração ou faria sentido somente se o assistidor fizesse mais coisas? De forma a realmente isolar algum tipo de regra "complexa"

solução!

Faz sentido a abstração, pois como dito acima:

nesse exemplo acredito que o provedor não precisa conhecer como reproduzir um vídeo. Logo, encapsulamos a regra de reprodução numa classe (o assistidor) e trocamos somente o provedor (YoutubeVideos, VimeoVideos, AluraVideos)