Pergunta

Uma das maneiras de implementar Dependency Injection corretamente é separar a criação do objeto da lógica de negócios. Normalmente, isso envolve o uso de uma fábrica para a criação do objeto.

Até este ponto, eu nunca considerou seriamente o uso de uma fábrica por isso peço desculpa se esta pergunta parece um pouco simplista:

Em todos os exemplos do padrão de fábrica que eu executar toda, eu sempre ver exemplos muito simples que não têm nenhuma parametrização. Por exemplo, aqui está uma fábrica roubado de excelente Misko de Hevery como pensar sobre o "artigo" operador nova.

class ApplicationBuilder {
  House build() {
    return new House(new Kitchen(
               new Sink(),
               new Dishwasher(),
               new Refrigerator())
           );
  }
}

No entanto, o que acontece se eu quero que cada casa que eu construir para ter um nome? Ainda estou usando o padrão de fábrica se eu re-escrever este código da seguinte forma?

class ApplicationBuilder {
  House build( const std::string & house_name) {
    return new House( house_name,
                      new Kitchen(new Sink(),
                                  new Dishwasher(),
                                  new Refrigerator())
                    );
  }
}

Note que a minha chamada de método de fábrica mudou a partir deste:

ApplicationBuilder builder;
House * my_house = builder.build();

Para isto:

ApplicationBuilder builder;
House * my_house = builder.build("Michaels-Treehouse");

A propósito: Eu acho que o conceito de separar objeto instanciação da lógica de negócios é grande, eu só estou tentando descobrir como posso aplicá-lo à minha própria situação. O que me confunde é que todos os exemplos que eu vi do padrão de fábrica não passar qualquer parâmetro para a função build ().

Para ser claro:. Eu não sei o nome da casa até o momento antes eu preciso instanciá-lo

Foi útil?

Solução

Eu vi um monte de exemplos que usam um conjunto fixo de argumentos, como no seu exemplo nome, e tê-los usado mim também e eu não posso ver nada de errado com ele.

No entanto, há uma boa razão que muitos tutoriais ou pequenos artigos evitarem mostrar fábricas que os parâmetros para a frente aos objetos construídos: É quase impossível de transmitir número arbitrário de argumentos (mesmo para um limite sane como 6 argumentos). Cada parâmetro que você tem para a frente para ser aceito como const T& e T& se você quiser fazê-lo genérico.

Para exemplos mais complicado, no entanto, é necessário um conjunto exponencialmente crescente de sobrecargas (para cada parâmetro, uma const e uma versão nonconst) e encaminhamento perfeito não é possível a todos (de modo que temporários são encaminhadas como temporários, por exemplo). Para o próximo padrão C ++ que problema está resolvido:

class ApplicationBuilder {
  template<typename... T>
  House *build( T&&... t ) {
    return new House( std::forward<T>(t)...,
                      new Kitchen(new Sink(),
                                  new Dishwasher(),
                                  new Refrigerator())
                    );
  }
};

Dessa forma, você pode chamar

builder.build("Hello", 13);

E ele irá retornar

new House("Hello", 13, new Kitchen(new Sink(...

Leia o artigo i ligada acima.

Outras dicas

Não consigo ver por que seria errado para adicionar este parâmetro para sua fábrica. Mas esteja ciente de que você não deve acabar adicionando muitos parâmetros que pode não ser útil para todos os objetos criados pela fábrica. Se você fizer isso, você terá perdido bastante as vantagens de uma fábrica!

Não é só é aceitável, mas é comum para passar parâmetros para um método de fábrica. Confira alguns exemplos . Normalmente, o parâmetro é um tipo contando a fábrica o que fazer, mas não há nenhuma razão você não pode adicionar outras informações que você precisa para construir um objeto. Eu acho que você está fazendo é bom.

A idéia de uma fábrica é que ele lhe dá uma instância de uma classe / interface, então não há nada de errado com passagem de parâmetros. Se houvesse, seria ruim para passar parâmetros para um novo () também.

Eu concordo com Benoit. Pense em uma fábrica para criar algo como conexões SQL, porém, em um caso como este seria necessário para passar informações sobre a conexão para a fábrica. A fábrica vai usar essa informação para utilizar o protocolo de servidor correto e assim por diante.

Claro, porque não ..!?

A coisa agradável sobre passagem de parâmetros é que ele permite que você esconda a implementação do objeto concreto. Por exemplo, no código que você postou você passar os parâmetros para o construtor. No entanto, você pode alterar a implementação de modo que eles são passadas através de um Initiailze método. Ao passar parâmetros para o método de fábrica que você esconde a natureza de construir e inicializar o objeto do chamador.

Dê uma olhada em Loki :: Factory, há uma implementação muito parecido com isso chegando para impulsionar o bem, no entanto. Alguns códigos de exemplo que eu uso regularmente em diferentes sabores:

typedef Loki :: SingletonHolder >>> ComponentFactory;

Isso pode parecer um pouco estranho à primeira vista, no entanto, deixe-me explicar esta besta e quão poderoso ele realmente é. Basicamente, criar um singleton que detém uma fábrica, o fora a maioria dos parâmetros são para o Singleton, Componente é o nosso produto, std :: string é o nosso tipo de criação id, depois desta segue uma lista de tipos dos parâmetros que é necessário para criação de Componentes (este pode ser definido utilizando uma macro, bem como para uma sintaxe menos extenso). Após esta linha pode apenas fazer:

ComponentFactory :: Instância () CreateObject ( "someStringAssociatedWithConcreteType", anDataCollection, aGamePointer);.

Para criar objetos, para registrar um só usar ComponentFactory :: Instância (). Register () ;. Há uma grande capítulo sobre os detalhes no livro de design ++ Modern C.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top