Как передать данные объектам, созданным с помощью Factory Method - PullRequest
2 голосов
/ 30 марта 2011

Я создаю серию объектов с помощью шаблона Factory Method.Примерно так:

class CMyFactory  
{
public:
    virtual CMyObject* MakeObject(ObjectType type);
}


CMyObject* CMyFactory::MakeObject(ObjectType type)
{
    CMyObject* newObject = NULL;
    switch (type)
    {
    case type1:
        newObject = new CType1Object;
        break;
    case type2:
        newObject = new CType2Object;
        break;

    // Other cases here
    }
    return newObject;
}

А теперь, предположим, я хочу передать некоторые данные конкретному созданному объекту.Эти данные будут разными в зависимости от типа объекта, который я хочу создать.

Есть ли чистый способ сделать это?

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

Есть идеи, как решить эту проблему?Может быть, шаблон Factory Method - это не то, что мне нужно?

Ответы [ 4 ]

2 голосов
/ 30 марта 2011

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

2 голосов
/ 30 марта 2011

Одна вещь, которую вы можете сделать, это передать ее конструктору, например:

class CMyFactory  
{
public:
    virtual CMyObject* MakeObject(ObjectType type, ParamType param);
}


CMyObject* CMyFactory::MakeObject(ObjectType type, ParamType param)
{
    CMyObject* newObject = NULL;
    switch (type)
    {
    case type1:
        newObject = new CType1Object(param);
        break;
    case type2:
        newObject = new CType2Object(param);
        break;

    // Other cases here
    }
    return newObject;
}

Вы можете перегрузить MakeObject в соответствии с типом параметра, например так:

class CMyFactory  
{
public:
    virtual CMyObject* MakeObject(ObjectType type, ParamType param);
    virtual CMyObject* MakeObject(ObjectType type, OtherParamType param);
}

CMyObject* CMyFactory::MakeObject(ObjectType type, ParamType param)
{
    CMyObject* newObject = NULL;
    switch (type)
    {
    case type1:
        newObject = new CType1Object(param);
        break;
    case type2:
        newObject = new CType2Object(param);
        break;

    // Other cases here
    }
    return newObject;
}


CMyObject* CMyFactory::MakeObject(ObjectType type, OtherParamType param)
{
    CMyObject* newObject = NULL;
    switch (type)
    {
    case type3:
        newObject = new CType3Object(param);
        break;
    case type4:
        newObject = new CType4Object(param);
        break;

    // Other cases here
    }
    return newObject;
}

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

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

Я согласен: вам не нужно передавать данныена объект после создания.Это равносильно двухэтапному созданию, которое как бы побеждает цель.

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

0 голосов
/ 30 марта 2011

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

В противном случае может быть использован механизм двойной диспетчеризации: вы хотите создать некоторый объект, поэтому данные должны быть совместимы.Однако двойная диспетчеризация не поддерживается в C ++, поэтому ее реализация (также с зависимостями) довольно сложна.

0 голосов
/ 30 марта 2011

Данные совершенно разные? Или объекты совершенно разные?

Например, все ли они транзакции, но одна - наличными, другая - чеком, а другая - кредитной картой? В каком случае будет некоторая общность данных (сумма, дата и т. Д.), А некоторые будут различны (например, номер карты)?

В этом случае вы можете создать базовый класс (например, CTransaction) и получить наследование для CCreditTransaction и т. Д. Затем ваш MakeObject может также взять объект CTransaction.

Если мы говорим о том, что CType1Object - это транзакция, а CType2Object - это элемент из системы инвентаризации, а CType3Object - это некий виджет, то я не думаю, что вам нужно будет корректировать свою реализацию.

Ваша фабрика может быть чем-то вроде MakeTransaction (...) и иметь отдельную фабрику для MakeWidget (...) и отдельную фабрику для MakeInventoryItem (...) и т.д.

...