Example - Factory method in C++

шаблоны проектирования, factory, method, C++

Discussion. Frameworks are applications (or subsystems) with "holes" in them. Each framework specifies the infrastructure, superstructure, and flow of control for its "domain", and the client of the framework may: exercise the framework's default behavior "as is", extend selected pieces of the framework, or replace selected pieces.

The Factory Method pattern addresses the notion of "creation" in the context of frameworks. In this example, the framework knows WHEN a new document should be created, not WHAT kind of Document to create. The "placeholder" Application::CreateDocument() has been declared by the framework, and the client is expected to "fill in the blank" for his/her specific document(s). Then, when the client asks for Application::NewDocument(), the framework will subsequently call the client's MyApplication::CreateDocument().


#include <iostream.h>

/* Abstract base class declared by framework */
class Document
{
  public:
    Document(char *fn)
    {
        strcpy(name, fn);
    }
    virtual void Open() = 0;
    virtual void Close() = 0;
    char *GetName()
    {
        return name;
    }
  private:
    char name[20];
};

/* Concrete derived class defined by client */
class MyDocument: public Document
{
  public:
    MyDocument(char *fn): Document(fn){}
    void Open()
    {
        cout << "   MyDocument: Open()" << endl;
    }
    void Close()
    {
        cout << "   MyDocument: Close()" << endl;
    }
};

/* Framework declaration */
class Application
{
  public:
    Application(): _index(0)
    {
        cout << "Application: ctor" << endl;
    }
    /* The client will call this "entry point" of the framework */
    NewDocument(char *name)
    {
        cout << "Application: NewDocument()" << endl;
        /* Framework calls the "hole" reserved for client customization */
        _docs[_index] = CreateDocument(name);
        _docs[_index++]->Open();
    }
    void OpenDocument(){}
    void ReportDocs();
    /* Framework declares a "hole" for the client to customize */
    virtual Document *CreateDocument(char*) = 0;
  private:
    int _index;
    /* Framework uses Document's base class */
    Document *_docs[10];
};

void Application::ReportDocs()
{
  cout << "Application: ReportDocs()" << endl;
  for (int i = 0; i < _index; i++)
    cout << "   " << _docs[i]->GetName() << endl;
}

/* Customization of framework defined by client */
class MyApplication: public Application
{
  public:
    MyApplication()
    {
        cout << "MyApplication: ctor" << endl;
    }
    /* Client defines Framework's "hole" */
    Document *CreateDocument(char *fn)
    {
        cout << "   MyApplication: CreateDocument()" << endl;
        return new MyDocument(fn);
    }
};

int main()
{
  /* Client's customization of the Framework */
  MyApplication myApp;

  myApp.NewDocument("foo");
  myApp.NewDocument("bar");
  myApp.ReportDocs();
}

Output

Application: ctor
MyApplication: ctor
Application: NewDocument()
   MyApplication: CreateDocument()
   MyDocument: Open()
Application: NewDocument()
   MyApplication: CreateDocument()
   MyDocument: Open()
Application: ReportDocs()
   foo
   bar
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
Support the author Donate
f
  • #
  • Aug. 9, 2019, 9:48 a.m.
  • (edited)

У метода NewDocument забыли указать возвращаемый тип (void). Я бы сделал бы сразу с проверочкой. И то что нет освобождение памяти, наверняка для обучающего материала это не хорошо.

    bool NewDocument(char *name)
    {
        if (_index >= 10) { return false; }
        cout << "Application: NewDocument()" << endl;
        /* Framework calls the "hole" reserved for client customization */

        _docs[_index] = CreateDocument(name);
        _docs[_index++]->Open();
        return true;
    }
    ~Application()
    {
        for (int i = _index - 1; i >= 0; --i) {
            delete _docs[i];
        }
    }

И вот по освобождению памяти у меня вопрос - как лучше сделать освобождение памяти?
1. Можно сделать как я показал выше (реализовать диструктор ~Application()).
2. Так как память выделялась в MyApplication, то было бы не плохо если бы она и освобождала память, тогда нужно добавить метод DeleteDocument:

    void DeleteDocument(Document *doc)
    {
        delete doc;
    }

А диструктор переписать:

    ~Application()
    {
        for (int i = _index - 1; i >= 0; --i) {
            DeleteDocument(_docs[i]);
        }
    }

И для меня смысл фабричного метода, это когда ты через указатель базового класса работаешь с разными дочернеми классами.
Например в массиве:

class Document {};

class Document1 : public Document {};

class Document2 : public Document {};

void main() {
    const int TYPE1 = 1;
    const int TYPE2 = 2;
    Document *m[10];
    for (int i = 0; i < 10; ++i) {
        int type;
        cin >> type;
        if (type == TYPE1) { m[i] = new Document1(); }
        else { m[i] = new Document2(); }
    }
    // some code
}

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Looking for a Job?
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

JuA
Sept. 17, 2019, 7:51 a.m.
Julija Aleksandrova

C++ - Test 001. The first program and data types

  • Result:33points,
  • Rating points-10
JuA
Sept. 17, 2019, 7:36 a.m.
Julija Aleksandrova

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:10points,
  • Rating points-10
VD
Sept. 16, 2019, 10:47 a.m.
Viktor Dzen'kiv

C++ - Test 002. Constants

  • Result:75points,
  • Rating points2
Last comments
Sept. 17, 2019, 5:07 a.m.
Misha Lebedev

Кстати интересные темы нашёл тут https://emacsway.github.io/ru/django-framework/#django-models Может что полезного тоже Евгений найдёте
Sept. 17, 2019, 3:50 a.m.
Misha Lebedev

Доброго времени суток. Спасибо за хороший ответ, У меня ситуация така что в галлереи будет несколько миллионов фотографий с фильтрами и тегами , и я опасаюсь за производительност . Это ос…
Sept. 17, 2019, 2:23 a.m.
Evgenij Legotskoj

Добрый день. Да, я тоже читал ту статью в своё время и согласен с тем, что внешние ключи гораздо лучше, чем GenericForeignKey. Выборки в ряде случае работают быстрее. Но лично мне про…
Sept. 14, 2019, 4:08 p.m.
Misha Lebedev

Приветствую вас Евгений , давно наблюда за развитием вашего замечательного портала, много полезно тут нашел , переодически зачитываюсь. Теперь по сушеству, делаю портал и там идеально ложи…
Sept. 10, 2019, 3:38 p.m.
Evgenij Legotskoj

function view для модели Article и LikeDislike.LIKE будет выглядеть так def like(request, pk): obj = Article.objects.get(pk=pk) try: likedislike = LikeDislike.objects.get(cont…
Now discuss on the forum
p
Sept. 17, 2019, 4:02 a.m.
pstMem

Да, действительно нужно дебажить, по другому не словить исключение. Уже решил проблему, был выход за предел массива, не правильные входные данные, так что всегда проверяйте размер массива.
Sept. 17, 2019, 2:39 a.m.
Evgenij Legotskoj

Добрый день! На удалённом сервере вряд ли. Этот класс из core модуля, а удалённый сервер - это ещё и network модуль нужно подтягивать. Тут на удалэнном сервере нужно делать программу…
Sept. 17, 2019, 2:30 a.m.
Evgenij Legotskoj

Добрый день! Попробуйте toHex() А также создние QString с помощью from методов. Может быть QString::fromLatin1(). В документации на QString почти два десятка методов from, один из них…
m
Sept. 16, 2019, 12:54 p.m.
mihamuz

Однозначно PostgreSql не ниже 10 ки.
R
Sept. 16, 2019, 6:09 a.m.
RED_Spider

прочитайте https://doc.qt.io/archives/qt-5.11/osx-deployment.html QMAKE_POST_LINK += "~/Qt/5.12.0/clang_64/bin/macdeployqt $${TARGET}.app $$escape_expand( \\n\\t )"
EVILEG
About
Services
© EVILEG 2015-2019
Recommend hosting TIMEWEB