Comment concevoir une fabrique d'objets C ++ simple?
Dans ma demande, il y a 10 à 20 classes qui sont instancié qu'une seule fois[*]. Voici un exemple:
class SomeOtherManager;
class SomeManagerClass {
public:
SomeManagerClass(SomeOtherManager*);
virtual void someMethod1();
virtual void someMethod2();
};
Les Instances des classes sont contenues dans un objet:
class TheManager {
public:
virtual SomeManagerClass* someManagerClass() const;
virtual SomeOtherManager* someOtherManager() const;
/** More objects... up to 10-20 */
};
Actuellement TheManager utilise le nouveau opérateur afin de créer des objets.
Mon intention est d'être en mesure de remplacer, à l'aide de plugins, la SomeManagerClass (ou toute autre classe) mise en œuvre par un autre. Afin de remplacer la mise en œuvre, 2 étapes sont nécessaires:
- Définir une classe DerivedSomeManagerClass, qui hérite SomeManagerClass [plugin]
- Créer la nouvelle classe (DerivedSomeManagerClass) au lieu de la valeur par défaut (SomeManagerClass) [application]
Je suppose que j'ai besoin d'un certain type de l'objet d'usine, mais il devrait être assez simple car il n'y a toujours qu'un seul type de création (la valeur par défaut de la mise en œuvre ou de l'utilisateur mise en œuvre).
Une idée sur la manière de concevoir une simple usine comme je viens de décrire? Considérez le fait qu'il pourrait y avoir plus de classes dans l'avenir, il devrait donc être facile à étendre.
[*] Je n'ai pas de soins si elle survient plus d'une fois.
Edit: Veuillez noter qu'il y a plus de deux objets qui sont contenues dans TheManager.
source d'informationauteur kshahar
Vous devez vous connecter pour publier un commentaire.
Je pense qu'il y a deux problèmes distincts se posent ici.
Un problème est: comment TheManager nom la classe qu'il a créer? Il doit tenir une sorte de pointeur vers "un moyen de créer la classe". Les solutions possibles sont:
L'autre problème est: qu'est-ce que cette "façon de créer une classe"? Malheureusement nous ne pouvons pas stocker des pointeurs vers les constructeurs directement, mais nous pouvons:
Modèles peuvent aider à éviter la duplication de code dans les deux cas.
En supposant une classe (plugin1) qui hérite de SomeManagerClass, vous avez besoin d'une hiérarchie de classes à construire votre types:
Ensuite, vous pouvez affecter ces usines pour un std::map, où ils sont liés à des chaînes
Enfin votre TheManager juste besoin de savoir le nom du plugin (comme une chaîne de caractères) et peut retourner un objet de type SomeManagerClass avec juste une ligne de code:
MODIFIER: Si vous n'aimez pas avoir un plugin usine de classe pour chaque plugin, vous pouvez modifier le modèle précédent avec cette:
Je pense que c'est une bien meilleure solution. En outre, le 'plugin_factory' classe peut ajouter lui-même à la "factory_map' si tu passes costructor la chaîne.
J'ai répondu dans un autre DONC, la question sur le C++ usines. Veuillez voir il y si un flexible de l'usine est de l'intérêt. J'essaie de décrire une ancienne façon de ET++ pour utiliser les macros qui a beaucoup travaillé pour moi.
ET++ était un projet de port vieux MacApp C++ et X11. Dans l'effort de Eric Gamma etc commencé à penser à Modèles de Conception
Je voudrais créer une "base" de l'usine qui a des méthodes virtuelles pour la création de tous les gestionnaires de base, et de laisser le "meta manager" (TheManager dans votre question) prendre un pointeur vers la base de l'usine comme un paramètre de constructeur.
Je suis en supposant que la "fabrique" pouvez personnaliser les instances de CXYZWManager par qui en découlent, mais il est aussi le constructeur de CXYZWManager pourrait prendre différents arguments dans la "coutume" de l'usine.
Un long exemple de code qui affiche "CSomeManager" et "CDerivedFromSomeManager":
Voici la solution que j'ai pensé, c'est pas le meilleur, mais peut-être cela aidera à réfléchir à de meilleures solutions:
Pour chaque classe, il y aurait un créateur de classe:
Puis, les créateurs seront réunis dans une même classe:
Et TheManager sera créé avec TheCreator de création interne:
Le problème avec cette solution est qu'il viole le SEC - pour chaque classe de créateur que j'aurais à écrire setter/getter dans TheCreator.
Ce semble qu'il serait beaucoup plus simple avec la fonction de template, par opposition à un Résumé de l'Usine modèle
Si vous voulez obtenir via une chaîne de caractères, vous pouvez créer une carte standard à partir de chaînes à des pointeurs de fonction. Voici une application qui fonctionne:
MODIFIER: En lisant les autres réponses, j'ai réalisé que ce est très similaire à Dave Van den Eynde FactorySystem solution, mais je suis en utilisant un modèle de fonction pointeur au lieu d'instancier basé sur un modèle de classes usine. Je pense que ma solution est un peu plus léger. En raison des fonctions statiques, le seul objet qui est instanciée est la carte en elle-même. Si vous avez besoin de l'usine pour effectuer d'autres fonctions (DestroyManager, etc.), Je pense que sa solution est plus extensible.
Vous pourriez mettre en œuvre une fabrique d'objet avec des méthodes statiques qui renvoient à une instance d'un Gérant de Classe. Dans l'usine, vous pouvez créer une méthode pour le type par défaut de gestionnaire et d'une méthode pour n'importe quel type de gestionnaire, vous donner un argument représentant le type de Gestionnaire de Classe (avec un enum). Cette dernière méthode doit retourner une Interface plutôt qu'une Classe.
Edit: je vais essayer de donner un peu de code, mais l'esprit que mon C++ temps sont tout à fait un certain temps et je suis en train de faire seulement de Java et de quelques scripts pour le moment.
Maintenant, vous devriez être en mesure d'appeler l'Usine via (si vous avez été en mesure de prendre l'exemple de code du travail):
Je voudrais utiliser des modèles comme ça que je peux pas voir le point de fabriques de classes:
Vous devriez jeter un oeil au tutoriel
http://downloads.sourceforge.net/papafactory/PapaFactory20080622.pdf?use_mirror=fastbull
Il contient un tutoriel sur la mise en œuvre d'un Résumé de l'usine en C++ et le code source qui est livré avec, il est également très robuste
Chris
Mh je ne comprends pas à cent pour cent, et je ne suis pas vraiment dans l'usine des trucs à partir de livres et d'articles.
Si tous vos gestionnaires partagent une même interface vous pourrait dériver d'une classe de base, et l'utilisation de cette classe de base dans votre programme.
Selon l'endroit où la décision qui classe sera créée sera fait, vous devez utiliser un identifiant pour la création (comme indiqué ci-dessus) ou la poignée de la décision du gérant de l'instancier en interne.
Une autre solution serait de mettre en œuvre la "politique" comme à l'aide de modèles. De sorte que Vous ManagerClass::create() renvoie un spécifique SomeOtherManagerWhatever instance. Cela permettrait de poser la décision du gérant à effectuer dans le code qui utilise votre Manager - Maye ce n'est pas prévu.
Ou de cette façon:
(ou quelque chose comme ça)
Avec cette construction, vous pouvez facilement utiliser d'autres gestionnaires en changeant seulement l'instanciation de MyAwesomeClass.
Aussi Une classe pour cet objet pourrait être un peu plus haut. Dans votre cas, une usine de fonction devrait le faire je pense. Eh bien, c'est plus une question de préférence personnelle.
Si vous comptez sur le soutien des plugins qui sont liés de façon dynamique, votre programme aura besoin pour fournir une base stable ABI (Application Binary Interface), ce qui signifie que vous ne pouvez pas utiliser le C++ votre interface principale comme C++ n'a pas de norme ABI.
Si vous voulez plugins d'implémenter une interface, vous définissez vous-même, vous devrez fournir le fichier d'en-tête de l'interface du plugin programmeur et standardiser sur un très simple C de l'interface afin de créer et de supprimer l'objet.
Vous ne pouvez pas fournir une bibliothèque dynamique qui vous permettra à "la nouvelle" la classe de plugin. C'est pourquoi vous avez besoin de standardiser sur une interface C pour créer l'objet. À l'aide de l'objet C++ est alors possible tant qu'aucun de vos arguments utilisez éventuellement des types incompatibles, comme des conteneurs STL. Vous ne serez pas en mesure d'utiliser un vecteur renvoyé par une autre bibliothèque, parce que vous ne pouvez pas garantir que leur STL mise en œuvre est la même que la vôtre.
Manager.h
PluginManager.h
PluginManager.cpp
Vous navez pas parler de TheManager. Il semble que vous souhaitez que le contrôle de la classe est utilisé? ou peut-être essayez-vous à la chaîne d'ensemble?
Il semble que vous besoin d'une classe de base abstraite et un pointeur vers le actuellement utilisés en classe. Si vous souhaitez de la chaîne, vous pouvez le faire dans les deux classe abstraite et themanager classe. Si la classe abstraite, ajouter un membre à la classe suivante dans la chaîne, si themanager puis de les trier dans l'ordre que vous souhaitez utiliser dans la liste. Vous aurez besoin d'un moyen pour ajouter des classes de sorte que vous aurez besoin d'un addMe() dans themanager. Il semble que vous savez ce que vous faites, de sorte w/e que vous choisissez doit être à droite. Une liste avec un addMe func est ma recommandation et si vous voulez seulement 1 classe active alors une fonction dans TheManager de décider qu'il serait bon.
Ce peut-être plus lourd que vous avez besoin, mais il semble que vous essayez de créer un cadre de travail de classe qui prend en charge les plugins.
Je voudrais diviser en 3 sections.
1) Le Cadre de la classe propres plugins.
Cette classe est responsable pour la publication des interfaces fournies par les plugins.
2) Une classe de PlugIn l'componets que de faire le travail.
Cette classe est responsable de l'enregistrement de la exporté des interfaces, et la liaison importées interfaces des composants.
3) La troisième section, la componets sont les fournisseurs et les consommateurs de ces interfaces.
Pour rendre les choses extensible, faire les choses en place et en cours d'exécution peut être rompu en plusieurs étapes.
À briser les choses.
Voici un minimum de modèle de fabrique de mise en œuvre qui m'est venu dans environ 15 minutes. Nous utilisons un similaire qui utilise le plus avancé des classes de base.
Il suffit de copier & coller sur une première application console Win32 dans VS2005/2008. Je tiens à souligner quelque chose: