L'objectif d'une usine est de déterminer, au moment de l'exécution et donc potentiellement et souvent avec des données indisponibles lors de la compilation, lesquels de class
10, tous dérivés d'une classe spécifique avec virtual
méthodes, devraient capturer ces données pour votre programme. Le fait est que les fonctionnalités de langage polymorphes vous permettent de travailler avec différents types de données (partageant une classe de base commune), en invoquant les comportements appropriés au type. Pour en bénéficier, vous devez avoir des objets de différents types dérivés. Lorsque vous apprenez à ce sujet dans un cours Comp Sci, vous probablement coder en dur la création de quelques-uns des types dérivés et jouer avec eux à travers des pointeurs vers la classe de base. Dans les problèmes complexes du monde réel, plutôt que dans la création codée en dur, il est souvent provoqué par les données provenant des entrées du programme, telles que les tables de base de données, les fichiers et les sockets. En fonction de ce que vous voyez exactement à chaque point, vous voulez créer un objet correctement typé pour le représenter, mais vous devrez probablement conserver un enregistrement de celui-ci en utilisant un type connu à la compilation: le pointeur vers la classe de base. Ensuite, non seulement vous pouvez préformer les opérations promues par la classe de base - dont certaines peuvent impliquer l'envoi dynamique à l'implémentation de la classe dérivée, mais vous pouvez aussi - si nécessaire - déterminer exactement le type réel des données et appeler les actions en conséquence .
Par exemple, supposons que vous lisez le fichier suivant, qui montre comment vous avez recueilli différents types de données pour chaque:
elephant name Tip-Toes partner Mega
mule name Dare-You mane_length 132
Vous avez la hiérarchie de classe suivante pour représenter ceux-ci:
struct Animal
{
Animal(const std::string& name) : name_(name) { }
virtual void eat_from(Supplies&) = 0; // animals must do in their own way...
virtual bool can_jump() { return false; } // some animals might, assume not...
std::string name_;
};
struct Elephant : Animal
{
Elephant(const std::string& name, const std::string& partner)
: Animal(name), partner_(partner)
{ }
std::string partner_;
virtual void eat_from(Supplies&) { supplies.consume(Tofu, 10 * kg); }
void swing_trunk(); // something specific to elephants
};
struct Mule : Animal
{
Mule(const std::string& name, double kgs) : Animal(name), kilograms_(kgs) { }
double kilograms_;
virtual void eat_from(Supplies&) { supplies.consume(Grass, 2 * kg); }
virtual bool can_jump() { return true; }
};
le travail de méthode d'usine est de distinguer l'éléphant de mule et retourner un nouvel objet du type approprié (dérivé - mais pas seulement - des animaux):
Animal* factory(std::istringstream& input)
{
std::string what, name;
if (input >> what && input >> name)
{
if (what == "elephant")
{
std::string partner;
if (input >> partner)
return new Elephant(name, partner);
}
else if (what == "mule")
{
double mane_length;
if (input >> mane_length)
return new Mule(name, mane_length);
}
}
// can only reach here on unparsable input...
throw runtime_error("can't parse input");
}
Vous pouvez stocker des animaux * s et effectuer des opérations sur les:
std::vector<Animal*> animals;
// we expect 30 animals...
for (int i = 0; i < 30; ++i) animals.push_back(factory(std::cin));
// do things to each animal...
for (int i = 0; i < 30; ++i)
{
Animal* p_unknown = animals[i];
std::cout << p_unknown->name() << '\n';
if (Elephant* p = dynamic_cast<Elephant*>(p_unknown))
p->swing_trunk();
}
Pour revenir à votre question:
Je travaille actuellement sur un projet où j'ai une classe et d'utiliser la constructeur pour initialiser un objet (duh!) mais il peut échouer et ne pas s'initialiser du tout. J'ai une propriété Success pour vérifier si elle a été créée correctement. Est-ce un bon exemple pour quand une classe d'usine devrait être mise en application? De cette façon, la méthode Create() peut retourner null et je peux me débarrasser de la propriété Success. Ai-je la bonne idée?
Non, pas une situation où une usine est utile, car il y a toujours un seul type impliqué. Il suffit de s'en tenir à ce que vous avez (dans un sens OO), mais vous pouvez choisir de lancer une exception, annuler le programme, etc. plutôt que de définir un drapeau que l'appelé peut ou ne peut pas vérifier.
en usine ou en usine? – Bozho