Question

L’un des moyens de mettre en œuvre correctement l’injection de dépendance consiste à séparer la création d’objets de la logique d’entreprise. Cela implique généralement l’utilisation d’une fabrique pour la création d’objets.

Jusqu'à présent, je n'avais jamais envisagé sérieusement d'utiliser une usine. Je m'excuse si cette question semble un peu simpliste:

Dans tous les exemples de modèles d'usine que j'ai rencontrés, je vois toujours des exemples très simples sans paramétrage. Par exemple, voici une usine volée de de l'excellent de Misko Hevery Comment penser au &" nouveau & "; Opérateur article.

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

Cependant, que se passe-t-il si je veux que chaque maison que je construise ait un nom? Est-ce que j'utilise toujours le motif Factory si je réécris ce code comme suit?

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

Notez que mon appel à la méthode Factory a changé:

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

À ceci:

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

Au fait: je pense que le concept de séparation de l'instanciation d'objet de la logique métier est génial. J'essaie simplement de comprendre comment je peux l'appliquer à ma propre situation. Ce qui me dérange, c’est que tous les exemples que j’ai vu du modèle Factory ne transmettent jamais de paramètres à la fonction build ().

Pour être clair: je ne connais pas le nom de la maison avant le moment où je dois l’instancier.

Était-ce utile?

La solution

J'ai vu pas mal d'exemples qui utilisent un ensemble d'arguments fixe, comme dans votre exemple de nom, et je les ai moi-même utilisés et je ne vois rien d'anormal.

Cependant, il existe une bonne raison pour que de nombreux tutoriels ou petits articles évitent de montrer des usines qui transmettent des paramètres aux objets construits: Il est pratiquement impossible de transmettre un nombre arbitraire d'arguments (même pour une limite raisonnable, comme 6 arguments). Chaque paramètre que vous transmettez doit être accepté en tant que const T& et T& si vous souhaitez le faire générique.

Toutefois, pour des exemples plus complexes, vous avez besoin d’un ensemble de surcharges de plus en plus important (pour chaque paramètre, une version const et une version non const) et transmission parfaite n'est pas du tout possible (de sorte que les données temporaires sont transférées comme temporaires, par exemple). Pour le prochain standard C ++, ce problème est résolu:

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

De cette façon, vous pouvez appeler

builder.build("Hello", 13);

Et il reviendra

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

Lisez l'article que j'ai lié ci-dessus.

Autres conseils

Je ne vois pas pourquoi il serait faux d’ajouter ce paramètre à votre usine. Mais sachez que vous ne devriez pas finir par ajouter de nombreux paramètres qui pourraient ne pas être utiles pour tous les objets créés par la fabrique. Si vous le faites, vous perdrez beaucoup des avantages d’une usine!

Non seulement est-il acceptable, mais il est commun de transmettre des paramètres à une méthode fabrique. Découvrez quelques exemples . Normalement, le paramètre est un type indiquant à la fabrique ce qu'il doit faire, mais rien ne vous empêche d'ajouter d'autres informations nécessaires à la création d'un objet. Je pense que ce que tu fais est bien.

L’idée d’une fabrique est qu’elle vous donne une instance de classe / interface, il n’ya donc rien de mal à passer des paramètres. S'il y en avait, il serait également mauvais de transmettre les paramètres à new ().

Je suis d'accord avec Benoit. Pensez à une usine pour créer quelque chose comme des connexions SQL bien que, dans un tel cas, il serait nécessaire de transmettre des informations sur la connexion à l’usine. L’usine utilisera ces informations pour utiliser le protocole de serveur approprié, etc.

.

Bien sûr, pourquoi pas ..!?

L’avantage de transmettre des paramètres est qu’il vous permet de masquer l’implémentation de l’objet concret. Par exemple, dans le code que vous avez publié, vous transmettez les paramètres au constructeur. Toutefois, vous pouvez modifier l’implémentation afin qu’elle soit transmise via une méthode Initiailze . En transmettant des paramètres à la méthode d'usine, vous masquez la nature de la construction et de l'initialisation de l'objet à l'appelant.

Jetez un coup d'œil à Loki :: Factory, il y a une implémentation qui ressemble beaucoup à celle de Boost, cependant. Quelques exemples de code que j'utilise régulièrement dans différentes saveurs:

typedef Loki :: SingletonHolder < Loki :: Factory & Lt; Composant, std :: string, Loki :: Liste de types & Lt; const DataCollection & amp ;, Loki :: Liste de types < Jeu *, Loki :: NullType & Gt; > > > ComponentFactory;

Cela peut sembler un peu bizarre à première vue, mais laissez-moi vous expliquer cette bête et sa puissance. Fondamentalement, nous créons un singleton qui contient une usine, la plupart des paramètres sont pour le singleton, Component est notre produit, std :: string est notre type de création id, après cela suit une liste de types des paramètres requis pour la création de composants. (ceci peut être défini en utilisant une macro aussi pour une syntaxe moins détaillée). Après cette ligne, on peut simplement faire:

ComponentFactory :: Instance (). CreateObject (" someStringAssociatedWithConcreteType " ;, anDataCollection, aGamePointer);

Pour créer des objets, pour en enregistrer un, utilisez ComponentFactory :: Instance (). Register () ;. Il existe un grand chapitre sur les détails dans le livre Modern C ++ Design.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top