Подходит ли здесь заводской метод? - PullRequest
1 голос
/ 12 июля 2010

Я создаю последовательность из Step объектов, которые различаются по типу и данным, содержащимся в нем.Например:

Объекты Step в основном должны быть структурами, которые выглядят следующим образом

{ GRAB, CASCADE_ONE, FACEUP, SOMEOTHERDATA },
{ DROP, DECK,  FACEDOWN, MOREDATA, ANDSOMEMORE },
{ MOVE, 34, 89 },

, где GRAB, MOVE и DROP указывают StepType:

typedef enum
{
     GRAB,
     DROP,
     MOVE
}StepType;

Как видите, в зависимости от StepType каждое из этих структур имеет переменное число полей данных после StepType.

Я планирую перебрать последовательность этих структур и выполнитьконкретное действие, основанное на поле StepType.Моя первая догадка - это должны быть объекты классов, производных от абстрактного Step класса, т. Е. Я должен создать GrabStep класс, MoveStep класс и DropStep класс.

Является ли этохороший дизайн, и если так, я должен создать их, используя фабричный метод?Если метод фабрики - это путь, то как инициализировать поля внутри объектов?

Ответы [ 3 ]

4 голосов
/ 12 июля 2010

Вам не нужен заводской шаблон для этого.Но создание абстрактного Step класса - хорошее начало:

class Step
{
private:
    // The presence of a pure virtual makes this class abstract.
    virtual void DoAction() = 0;
public:
    virtual ~Step() {} // Needed if you are going to delete via a Step* pointer
    void Action() { DoAction(); } // Template method pattern
};

// All other classes derive publicly from Step, since they all have an "is-a"
// relationship with Step (i.e. a GrabStep "is-a" Step).
class GrabStep : public Step
{
private:
    void DoAction() { /* Do whatever a GrabStep does */ };
    // Data relevant to GrabStep
};

class MoveStep : public Step
{
private:
    void DoAction() { /* Do whatever a MoveStep does */ };
    // Data relevant to MoveStep
};

class DropStep : public Step
{
private:
    void DoAction() { /* Do whatever a DropStep does */ };
    // Data relevant to DropStep
};

Затем вы можете выполнять итерации по этим вещам, не зная их точных типов:

// Example:
std::vector<Step*> seq; // or some other container
// Note that we are storing Step* pointers in a container instead of Step
// objects. This is needed for polymorphism to work.
// ...
seq.push_back(new GrabStep);
seq.push_back(new MoveStep);
seq.push_back(new DropStep);
// ...
for(std::vector<Step*>::iterator i = seq.begin(); i != seq.end(); ++i)
{
    // Will call the proper version of DoAction() depending on the actual type.
    (*i)->Action();
}
// ...
// After we are done, clean up after ourselves. This is needed because
// std::vector does not delete the pointees.
for(std::vector<Step*>::iterator i = seq.begin(); i != seq.end(); ++i)
{
    delete (*i); // Safe because Step has a virtual destructor.
}
1 голос
/ 12 июля 2010

Если вам нужен полиморфизм во время выполнения, то я думаю, что это хороший дизайн.Относительно фабричной функции: если ваши клиенты нуждаются в ней, напишите ее.Функция фабрики просто вызывает конструкторы подклассов.

1 голос
/ 12 июля 2010

Из звуков этого всего, что вам нужно, это какой-то полиморфизм, на который вы обращаетесь с абстрактным базовым классом.

Фабричный шаблон - это когда вызывающий не заботится о типеобъект, который им понадобится, только то, что он соответствует интерфейсу.Например, синтаксический анализатор файла конфигурации, который не заботится о том, где находится файл конфигурации или является ли он двоичным или XML.Все, что парсер хочет сделать, это прочитать элементы.

В вашем случае, какой бы код ни выбирал, какой тип шага для построения по определению заботится о том, какой тип объекта они создают.Вы все еще можете использовать шаблон фабрики, чтобы абстрагировать конструкцию, но вам потребуется одна фабричная функция (с соответствующими параметрами) для каждого типа шага.

В зависимости от того, какие методы вы используете, чтобы решить, какой тип шагачтобы построить, вы можете абстрагировать их в шаблон стратегии или аналогичный.

...