Реализация фабричного метода C

#c #qt #design-patterns

#c #qt #шаблоны проектирования

Вопрос:

Мне было интересно, выполняет ли этот фрагмент кода все, что запрашивает шаблон проектирования чистого фабричного метода? Это подготовка к моему последнему модулю программирования, и мне просто нужно убедиться, что это правильное применение шаблона проектирования.

 #include <QCoreApplication>
#include <QString>
#include <QDebug>

class Bread
{
public:
    virtual void print() = 0;
};

class WhiteBread: public Bread
{
public:
    void print() {
        qDebug() << "White bread";
    }
};

class BrownBread: public Bread
{
public:
    void print() {
        qDebug() << "Brown bread";
    }
};

class BreadFactory {
public:
    Bread* makeBread(QString type) {
        if (type == "White bread")
            return new WhiteBread();
        else if (type == "Brown bread")
            return new BrownBread();
    }
};


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    BreadFactory *breadFactory = new BreadFactory();
    Bread *breadType;

    breadType= breadFactory->makeBread("White bread");
    breadType->print();

    breadType = breadFactory->makeBread("Brown bread");
    breadType->print();

    return a.exec();
}
 

Комментарии:

1. Я думаю, что это называется «абстрактный фабричный метод». Если это то, что подразумевается, все в порядке. Но если имеется в виду действительно «чистый» (чисто виртуальный), то у вас, вероятно, должен быть абстрактный класс-предок с чисто виртуальным (без тела) фабричным методом и двумя наследующими конкретными классами с реализациями для этого метода с той же сигнатурой (включая абстрактный возвращаемый тип), но создающими объекты разных производных классовабстрактного возвращаемого типа фабричного метода.

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

3. кстати, отсутствует виртуальный деструктор, не весь путь возврата makeBread. и unique_ptr было бы лучше, чем необработанный указатель.

4. Спасибо за советы, так должен ли я создать абстрактную фабрику по производству хлеба, которая обрабатывает логику, и клиента, который создает абстрактную фабрику? Может ли кто-нибудь привести мне пример этой реализации? У меня нет большого опыта в ООП

Ответ №1:

  1. Вам не нужно создавать экземпляр BreadFactory . Просто используйте статический метод.
     class BreadFactory
    {
        public:
            static Bread* makeBread( QString type ) 
            {
            ...
            }
    };
    
    //in main 
    Bread *breadType = BreadFactory::makeBread( "White Bread"); 
    breadType->print();
     
  2. override Для наглядности используйте ключевое слово c 11.
     class WhiteBread : public Bread
    {
    public:
        void print() override{
    ...
     
  3. Используйте c 11 unique_ptr среди интеллектуальных указателей.
     static unique_ptr<Bread> makeBread( QString type ) {
        if ( type == "White bread" )
            return std::make_unique<WhiteBread>();
        else if ( type == "Brown bread" )
            return std::make_unique<BrownBread>();
        else
            return nullptr;
    }
     
  4. Используйте virtual деструктор.
     class Bread
    {
    public:
        virtual void print() = 0;
        virtual ~Bread() {};
    };
     

Ответ №2:

Реализация фабричного метода будет выглядеть следующим образом:

 class BreadMaker
{
 public:
   virtual Bread* makeBread() = 0;
}

class WhiteBreadMaker : public BreadMaker
{
public:
   Bread* makeBread();
}

// WhiteBreadMaker.cpp
Bread* WhiteBreadMaker::makeBread()
{
   return new WhiteBread();
}

// ***Similarly for BrownBreadMaker

// main.cpp
int main()
{
   BreadMaker *maker = new WhiteBreadMaker();    // or BrownBreadMaker

   Bread *bread = maker->makeBread();
   bread->print();    // prints "White Bread" or "Brown Bread" depending on the Factory class used.
}