Шаблон фабричного метода использует наследование, в то время как абстрактный фабричный шаблон использует композицию. Как?

Я просматриваю разницу между абстрактным фабричным шаблоном и фабричным методом. Я понял, что фабричный метод используется для создания только одного продукта, но абстрактная фабрика предназначена для создания семейств связанных или зависимых продуктов. Но как метод Factory использует наследование, в то время как абстрактный шаблон factory использует композицию, мне неясно.

Я знаю, что об этом спрашивали пару раз. Может ли кто-нибудь объяснить с помощью приведенного ниже кода, как происходит наследование и композиция?

Код заводского метода

class IRose
{
public:
virtual string Color(void)=0;
};

class RedRose: public IRose
{
public:
string Color(void)
{
    return "Red";
}
};

class YellowRose: public IRose
{
public:
string Color(void)
{
    return "Yellow";
}
};

class IFactory
{
public:
virtual IRose* Create(string type)=0; 
//The factory create method in 90% of cases will take a parameter which 
//determines what kind of the object the factory will return.   
};

class Factory: public IFactory
{
public:
IRose* Create(string type)
{
    if ("Red" == type)
        return new RedRose();

    if ("Yellow" == type)
        return new YellowRose();

    return NULL;
}
};

int main()
{
IRose* p = NULL;
IFactory* f = NULL;

f = new Factory();  //You have to create an INSTANCE of the factory

p = f->Create("Red");
cout<<"\nColor is: "<<p->Color()<<"\n";
delete p;
p = f->Create("Yellow");
cout<<"\nColor is: "<<p->Color()<<"\n";
delete p;
return 1;
}

Абстрактный заводской код.

class IFridge
{
public:
virtual string Run(void) = 0;
};

class FridgeSamsung : public IFridge
{
public:
string Run(void)
{
    return "You are now running Samsung Fridge\n";
}
};

class FridgeWhirlpool : public IFridge
{
public:
string Run(void)
{
    return "You are now running Whirlpool Fridge\n";
}
};

class IWashingMachine
{
public:
virtual string Run(void) = 0;
};

class WashingMachineSamsung : public IWashingMachine
{
public:
string Run(void)
{
    return "You are now running Samsung Washing Machine\n";
}
};

class WashingMachineWhirlpool : public IWashingMachine
{
public:
string Run(void)
{
    return "You are now running Whirlpool Washing Machine\n";
}
};

class IFactory
{
public:
virtual IFridge* GetFridge(void) = 0;
virtual IWashingMachine* GetWashingMachine(void) = 0;
};

class FactorySamsung : public IFactory
{
IFridge* GetFridge(void)
{
    return new FridgeSamsung();
}

IWashingMachine* GetWashingMachine(void)
{
    return new WashingMachineSamsung();
}
};

class FactoryWhirlpool : public IFactory
{
IFridge* GetFridge(void)
{
    return new FridgeWhirlpool();
}

IWashingMachine* GetWashingMachine(void)
{
    return new WashingMachineWhirlpool();
}
};

int main()
{
IFridge* fridge;    //Client just knows about fridge and washingMachine.
IWashingMachine* washingMachine; //and factory. He will write operations which
IFactory* factory; //work on fridges and washingMachines.

factory = new FactorySamsung; 
//This is the only place where the client
//has to make a choice. 

//The rest of the code below will remain same, even 
//if the factory is changed. He can change the factory and the same range
//of products but from a different factory will be returned. No need to 
//change any code.

fridge = factory->GetFridge();
cout << fridge->Run();
washingMachine = factory->GetWashingMachine();
cout << washingMachine->Run();
cout << "\n";

delete factory;
factory = new FactoryWhirlpool;

//See same client code.
fridge = factory->GetFridge();
cout << fridge->Run();
washingMachine = factory->GetWashingMachine();
cout << washingMachine->Run();
cout << "\n";
delete factory;
return 1;
}

person Deepak    schedule 18.07.2018    source источник
comment
Первый код не похож на типичный Factory Method для меня. Класс Factory с Create(string type) кажется слишком сложным и ненужным. Где ты взял код? Кроме того, где вы прочитали, что шаблон фабричного метода использует наследование, в то время как абстрактный фабричный шаблон использует композицию?   -  person guillaume31    schedule 18.07.2018
comment
@guillaume31 Шаблон фабричного метода использует наследование, в то время как абстрактный фабричный шаблон использует композицию. Эта тема обсуждалась в самом stackoverflow здесь   -  person Deepak    schedule 18.07.2018
comment
@guillaume31 Код, который я взял в качестве ссылки из здесь, если вы считаете, что это неправильно метод, пожалуйста, направьте на правильный.   -  person Deepak    schedule 18.07.2018
comment
Я нахожу это немного надуманным. Для более наглядного примера посмотрите пример кода Марка Симанна в вопросе SO, на который вы только что ссылались.   -  person guillaume31    schedule 18.07.2018
comment
Хорошо, в статье, из которой вы взяли код, есть большой недостаток, потому что, несмотря на то, что утверждает заголовок, он объясняет шаблон Factory, основной целью которого является извлечение сложной логики создания из конструктора в отдельный класс вместо Factory. Шаблон Method как таковой.   -  person guillaume31    schedule 18.07.2018
comment
В примере Марка Симанна в первом фрагменте кода (Abstract Factory) есть композиция из-за поля private readonly IMyFactory factory. Во втором коде (фабричный метод) нет композиции, потому что нет необходимости в поле-члене, все делается через наследование. Это так просто.   -  person guillaume31    schedule 18.07.2018
comment
@guillaume31 guillaume31 я проверил несколько источников шаблона Factory Method и обнаружил, что та же процедура используется другие, пожалуйста, поделитесь любой ссылкой, которая показывает правильный путь для шаблона Factory Method   -  person Deepak    schedule 18.07.2018
comment
@ guillaume31 guillaume31, если возможно, можете ли вы объяснить мне код C ++?   -  person Deepak    schedule 18.07.2018
comment
Википедия? ;)   -  person guillaume31    schedule 18.07.2018
comment
Я говорю о паттерне Фабричный метод из Банды четырех Книга выкроек здесь. В литературе по C++ может быть другой шаблон фабричного метода, но это не то, к чему спонтанно относится большинство разработчиков.   -  person guillaume31    schedule 18.07.2018


Ответы (1)


Это пересмотренный ответ после некоторых размышлений.

Фабричный метод. Обычно createObject() является методом объекта Creator.

Абстрактная фабрика. Обычно объект фабрики является атрибутом объекта Creator.

Теперь предположим, что createObject() и Factory Object принадлежат соответствующему Создателю.

Метод Factory: createObject() может изменяться в подклассах Creator. Это происходит путем изменения реализации creatObject() посредством наследования.

Абстрактная Фабрика: Объект Фабрики также может изменяться в подклассах Создателя. Однако это изменение происходит путем замены одного объекта Factory другим объектом Factory, т. е. объект Creator изменяется на композицию.

В вашей демонстрации creatObject() и Factory Object являются внешними по отношению к Создателю(ям), что скрывает различие между композицией и наследованием!

У Кристофера Охрави есть отличные видео на YouTube по выкройкам.

Фабричный метод https://www.youtube.com/watch?v=EcFVTgRHJLM&index=4&list=PLrhzvIcii6GNjpARdnO4ueTUAVR9eMBpc

Абстрактная фабрика https://www.youtube.com/watch?v=v-GiuMmsXj4&index=5&list=PLrhzvIcii6GNjpARdnO4ueTUAVR9eMBpc

По запросу вот версия Factory Method (на этот раз на C++!). Если вам нужна помощь в переводе, дайте мне знать.

class IRose
{
public:
    virtual const char * Color(void) = 0;
};

class RedRose : public IRose
{
public:
    const char * Color(void)
    {
        return "I am a Red rose";
    }
};

class YellowRose : public IRose
{
public:
    const char * Color(void)
    {
        return "I am a Yellow rose";
    }
};

class RoseGarden
{
protected: class IRose* rose;   // a pointer to the garden's rose

public:
    virtual void createRose() { }  // abstract Factory Method

public: void sayColor() {
        cout << rose->Color() << '\n';
    }
};

class RedRoseGarden : public RoseGarden
{
public:
    void createRose()
    {
        this->rose = new RedRose();   // concrete factory method
    }
};

class YellowRoseGarden : public RoseGarden
{
public:
    void createRose()
    {
        this->rose = new YellowRose();  // concrete factory method
    }
};

int main()
{
    RoseGarden * garden = NULL;

    garden = new YellowRoseGarden;
    garden->createRose();      // correct factory method is chosen via inheritance
    garden->sayColor();
    delete garden;

    garden = new RedRoseGarden;
    garden->createRose();      // correct factory method is chosen via inheritance
    garden->sayColor();
    delete garden;

    return 1;
}

Также здесь немного измененная версия Abstract Factory, чтобы лучше показать, как она используется. Только что добавил дом объект. Примечание. Я изменил все ваши «строковые» объекты на const char* для моего компилятора.

// make different types of fridges
class IFridge
{
public:
    virtual const char* Run(void) = 0;
};

class FridgeSamsung : public IFridge
{
public:
    const char* Run(void)
    {
        return "This house has a Samsung Fridge\n";
    }
};

class FridgeWhirlpool : public IFridge
{
public:
    const char* Run(void)
    {
        return "This house has a Whirlpool Fridge\n";
    }
};

// make different types of washing machine 
class IWashingMachine
{
public:
    virtual const char*  Run(void) = 0;
};

class WashingMachineSamsung : public IWashingMachine
{
public:
    const char* Run(void)
    {
        return "This house has a Samsung Washing Machine\n";
    }
};

class WashingMachineWhirlpool : public IWashingMachine
{
public:
    const char* Run(void)
    {
        return "This house has a Whirlpool Washing Machine\n";
    }
};

// make different type of factory
class IFactory
{
public:
    virtual IFridge* GetFridge(void) = 0;
    virtual IWashingMachine* GetWashingMachine(void) = 0;
};

class FactorySamsung : public IFactory
{
    IFridge* GetFridge(void)
    {
        return new FridgeSamsung();
    }

    IWashingMachine* GetWashingMachine(void)
    {
        return new WashingMachineSamsung();
    }
};

class FactoryWhirlpool : public IFactory
{
    IFridge* GetFridge(void)
    {
        return new FridgeWhirlpool();
    }

    IWashingMachine* GetWashingMachine(void)
    {
        return new WashingMachineWhirlpool();
    }
};

// Make a house object that has a fridge and a washing machine
class House
{
private:
    class  IWashingMachine * washingMachine;
    class  IFridge * fridge;

public:
    House(IFactory * houseFactory) {
        washingMachine = houseFactory->GetWashingMachine();
        fridge = houseFactory->GetFridge();
    }
    void showAppliances() {
        cout << washingMachine->Run();
        cout << fridge->Run();
    }
};

int main()
{
    class IFactory * factory;  
    class House * house;       

    // make a samsung house
    factory = new FactorySamsung;
    house = new House(factory);     // passing the factory by injection
    house->showAppliances();        // now we have a Samsung house
    cout << '\n';

    // clean up
    delete house;
    delete factory;

    // make a whirlpool house
    factory = new FactoryWhirlpool;
    house = new House(factory);    // passing the factory by injection
    house->showAppliances();       // now we have a WHilepool house
    cout << '\n';

    // clean up
    delete house;
    delete factory;

    return 1;
} 
person bcperth    schedule 19.07.2018
comment
если возможно, не могли бы вы изменить структуру приведенного выше кода фабричного метода, чтобы использовать наследование - person Deepak; 20.07.2018
comment
конечно - обычно я работаю на JS/PHP, поэтому настройка займет некоторое время. У меня есть несколько примеров PHP, если вы можете читать PHP? - person bcperth; 20.07.2018
comment
извините, вы не знакомы с JS/PHP, если вы найдете какую-либо ссылку, указывающую на вышеизложенное в C++, поделитесь ссылкой. - person Deepak; 20.07.2018
comment
ОК, я привык прыгать с одного языка на другой! Я могу легко перевести это на C++, но сделаю это завтра :-) - person bcperth; 20.07.2018
comment
большое спасибо, я понял о наследовании в фабричном методе. В случае абстрактного фабричного метода действительно ли требуется класс House? - person Deepak; 21.07.2018
comment
Теперь у меня возникает еще один вопрос о шаблоне проектирования. Можно ли изменить шаблон дизайна в соответствии с нашим удобством? Разве у них нет фиксированного формата? - person Deepak; 21.07.2018
comment
Основное преимущество шаблонов проектирования заключается в том, что они предоставляют решения для часто возникающих ситуаций способом, понятным многим людям. Поэтому, когда в ваших комментариях говорится ... с использованием фабричного метода, этого достаточно. С другой стороны, вы можете варьировать шаблон по своему усмотрению, при условии, что вы прокомментируете, что вы сделали и в чем причина. - person bcperth; 23.07.2018
comment
Что касается класса House, это просто для того, чтобы показать один из способов, которыми обычно используется абстрактная фабрика. Подклассы базового класса Client могут быть созданы с различными объектами Factory в соответствии с их тростником. В нашем случае House является клиентом (хотя в моем примере я не делал подкласс). Диаграмма UML в Wiki (en.wikipedia.org/wiki/Abstract_factory_pattern) показывает роль клиент и его подклассы. - person bcperth; 23.07.2018