Цель фабрики - определить во время выполнения и, следовательно, потенциально и часто с данными, недоступными во время компиляции программы, которые из многих class
всех, полученных из определенного класса с virtual
методами, должны захватывать эти данные для вашей программы.
Дело в том, что функции полиморфного языка позволяют работать с различными типами данных (совместно используя общий базовый класс), вызывая поведение, соответствующее типу. Чтобы извлечь выгоду из этого, вам нужно иметь объекты разных производных типов. Когда вы узнаете об этом в курсе Comp Sci, вы, вероятно, жестко создадите несколько из каждого типа Derived и поиграете с ними через указатели на базовый класс. В сложных реальных задачах, а не в жестком кодировании, оно часто вытесняется из данных, поступающих из входных данных программ, таких как таблицы базы данных, файлы и сокеты. В зависимости от того, что именно вы видите в каждой точке, вы хотите создать объект с соответствующей типизацией для его представления, но вам, вероятно, потребуется вести запись об этом с использованием известного типа во время компиляции: указатель на базовый класс. Затем вы можете не только предварительно выполнить операции, которые обещает базовый класс - некоторые из которых могут включать динамическую диспетчеризацию для реализации производного класса, но вы также можете - при необходимости - точно определить, каков реальный тип данных, и соответствующим образом вызвать действия .
Например, скажем, вы прочитали следующий файл, который показывает, как вы собрали различные типы данных для каждого:
elephant name Tip-Toes partner Mega
mule name Dare-You mane_length 132
У вас есть следующая иерархия классов, чтобы представить их:
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; }
};
Задача фабричного метода состоит в том, чтобы отличать слона от мула и возвращать новый объект соответствующего типа (полученный из - но не просто - животного):
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");
}
Затем вы можете хранить * Животных и выполнять над ними операции:
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();
}
Возвращаясь к вашему вопросу:
В настоящее время я работаю над проектом, в котором у меня есть класс, и я использую конструктор для инициализации объекта (дух!), Но он может завершиться неудачей и вообще не инициализироваться. У меня есть свойство Success, чтобы проверить, правильно ли оно было создано. Это хороший пример того, когда должен быть реализован фабричный класс? Таким образом, метод Create () может вернуть ноль, и я могу избавиться от свойства Success. У меня есть правильная идея?
Нет, не ситуация, когда фабрика полезна, так как задействован только один тип. Просто придерживайтесь того, что у вас есть (в смысле ОО), но вы можете выбрать исключение, отменить программу и т. Д., А не устанавливать флаг, который вызываемый может или не может проверить.