Injeção de dependência: em que momento tenho permissão para criar um novo objeto?

13

Estou refatorando um aplicativo PHP e estou tentando fazer o máximo possível de injeção de dependência (DI).

Sinto que tenho uma boa noção de como funciona e certamente posso ver minhas aulas se tornando muito mais enxutas e robustas.

Estou refatorando para injetar uma dependência em vez de criar um novo objeto dentro da classe, mas em algum momento terei que criar alguns objetos, ou seja, use a newpalavra-chave temida .

O problema que encontrei agora é em que ponto posso realmente criar novos objetos? Parece que vou terminar em uma classe de nível superior, criando um monte de novos objetos, pois não há mais para onde ir. Isso parece errado.

Li alguns blogs que usam classes de fábrica para criar todos os objetos e você injeta a fábrica em outras classes. Você pode chamar os métodos de fábrica, e a fábrica cria o novo objeto para você.

Minha preocupação em fazer isso agora é que minhas aulas de fábrica serão newgratuitas para todos! Eu acho que isso pode ser bom, pois são classes de fábrica, mas existem algumas regras a serem seguidas ao usar um padrão de fábrica e DI, ou estou indo muito longe aqui?

Gaz_Edge
fonte
Eu recomendo a IoC para serviços e políticas. Para classes de modelo ou auxiliar, eu simplesmente usaria new. É claro que existem alguns pontos de entrada nos quais você precisa chamar o contêiner de IoC, mas não deve haver muitos. Normalmente, você configura o IoC uma vez e depois pede que uma classe seja resolvida por solicitação. No caso do MVC, normalmente é o controlador.
CodesInChaos
A classe de nível superior mencionada faz parte da raiz da composição. Está longe de estar errado.
Facio Ratio 6/11/11

Respostas:

12

Depois de pesquisar um pouco sobre isso, parece que (como mencionado em um comentário acima) a classe de nível superior de que eu estava falando se chama Raiz de Composição .

De fato, parece ser a solução aceita adicionar a criação de todos os objetos nessa raiz de composição (ou fazer referência a um contêiner de IoC daqui).

Minha preocupação original com isso era que essa classe de nível superior acabaria sendo um pouco confusa. Isso é verdade até certo ponto, mas os profissionais pesam os contras. Por exemplo, posso ver a legibilidade, testabilidade e capacidade de manutenção de todas as minhas outras classes.

A classe de nível superior pode ser um pouco confuso, cheio de newe set_property()mas eu tenho que dizer que eu realmente prefiro ter todo este código em um só lugar, em vez de espalhados por todo as outras classes

Outra página útil discutindo resultados de desempenho desse método aqui

Gaz_Edge
fonte
1
+1 porque nunca ouvi falar em 'Composition Root' antes.
#maker
2

Uma classe de fábrica terá newaspergida nela. Seria criar qualquer objeto que você está solicitando e provavelmente as dependências desse objeto. Como o trabalho das fábricas é instanciar o objeto correto para você ter newnesta classe não é uma coisa ruim.

O DI é para que você tenha um design fracamente acoplado. Você pode fazer alterações em seu aplicativo alterando a dependência fornecida a cada objeto. Tornando seu aplicativo flexível, extensível e fácil de testar.

No nível superior, você terá um código que instanciará algumas fábricas, configurará conexões com os serviços e enviará uma resposta. Ele terá uma quantidade razoável de newchamadas estáticas para instanciar objetos necessários para o seu aplicativo. É aí que isso pertence.

Schleis
fonte
-2

Meus dois centavos aqui:

Estou refatorando um aplicativo php e estou tentando fazer o máximo possível de injeção de dependência

Você não informa se está usando uma estrutura de injeção de dependência. Eu acho que você definitivamente deveria. Use algo que ofereça os recursos necessários: /programming/9348376/guice-like-dependency-injection-frameworks-in-php .

O problema que encontrei agora é em que ponto posso realmente criar novos objetos? Parece que vou terminar em uma classe de nível superior, criando muitos objetos novos, pois não há mais para onde ir. Isso parece errado.

Você normalmente usa a configuração ou um ponto central para a instanciação dos objetos iniciais que compõem seu aplicativo. O contêiner criará os objetos para você.

Você acessa objetos (serviços, provedores, controladores ...) por meio do contêiner de IoC. Ele criará um objeto de forma transparente, se necessário, ou fornecerá uma referência à instância existente apropriada.

Obviamente, dentro de sua implementação específica de objetos, você pode instanciar outros objetos nos quais não precisa de DI (estruturas de dados, tipos personalizados, etc.), mas isso é programação normal.

Li alguns blogs que usam classes de fábrica para criar todos os objetos e você injeta a fábrica em outras classes. Você pode chamar os métodos de fábrica e a fábrica cria o novo objeto para você.

Normalmente, você usa um Factory se deseja que a estrutura de IoC instancie alguns objetos de IoC através de suas fábricas (isso é necessário ao instanciar um objeto em particular, requer algum trabalho extra). Se você pode simplesmente criar seus objetos com "new Object ()" e definir algumas propriedades, não necessariamente deseja usar um padrão de Fábrica.

Em outras palavras, eu diria que o uso de um padrão Factory para uma classe ou grupo de classes depende de como você deseja modelar essas classes, não de usar DI (a menos que sua implementação de DI exija explicitamente fábricas, o que é incomum).

Você também configura sua estrutura de IoC para usar um Factory quando estiver usando uma biblioteca de terceiros que já exija o uso de um Factory. Nesse caso, você não tem controle sobre isso e precisa informar ao seu contêiner de IoC: "ei, quando solicito uma dessas interfaces, você deve usar esta fábrica para fornecer uma instância apropriada".

Minha preocupação em fazer isso agora é que minhas aulas de fábrica serão uma nova opção para todos! Eu acho que isso pode ser bom, pois são classes de fábrica, mas existem algumas regras a serem seguidas ao usar o padrão de fábrica e o DI, ou estou indo muito longe aqui.

Nesse caso, parece que você não precisa usar padrões de fábrica para esses objetos / serviços / controladores / o que quer que seja, e você pode simplesmente configurar sua IoC para instanciar com "nova" a classe apropriada e injetar todo o resto.

Espero que ajude.

jjmontes
fonte
obrigado pela resposta, mas certamente o contêiner de IoC é a 'classe de nível superior' a que eu estava me referindo. Se eu conseguir criar objetos lá, será uma bagunça certa.
Gaz_Edge 31/10
4
doing DI manually beats the whole purpose of using an Inversion of Control container- Se com isso você quer dizer "... que está centralizando suas dependências em um arquivo de configuração", então você está certo, porque isso é tudo que um contêiner de IoC realmente faz. O objetivo real do DI é desacoplar, e você pode fazer isso fornecendo suas dependências em um método construtor. Você não precisa de uma estrutura de DI para fazer isso.
Robert Harvey
mmm, você não cria objetos, solicita-os ao contêiner de IoC (de qualquer lugar que precise) ou usa injeção de campo / argumento para que suas classes sejam injetadas automagicamente nas classes apropriadas, criadas sempre pelo contêiner de IoC.
Jjmontes # 31/13
1
Concordo que você precisa de uma estrutura para aplicativos muito grandes . Muitos aplicativos não são tão grandes e não se beneficiam da complexidade adicional do uso de uma estrutura de DI.
Robert Harvey
2
Eu não disse que era. Eu simplesmente disse que você não precisa de um contêiner de DI para fazer isso.
Robert Harvey