Evgenii Legotckoi
Sept. 24, 2018, 6:23 p.m.

Example - Factory method in C++

Content

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().


  1. #include <iostream.h>
  2.  
  3. /* Abstract base class declared by framework */
  4. class Document
  5. {
  6. public:
  7. Document(char *fn)
  8. {
  9. strcpy(name, fn);
  10. }
  11. virtual void Open() = 0;
  12. virtual void Close() = 0;
  13. char *GetName()
  14. {
  15. return name;
  16. }
  17. private:
  18. char name[20];
  19. };
  20.  
  21. /* Concrete derived class defined by client */
  22. class MyDocument: public Document
  23. {
  24. public:
  25. MyDocument(char *fn): Document(fn){}
  26. void Open()
  27. {
  28. cout << " MyDocument: Open()" << endl;
  29. }
  30. void Close()
  31. {
  32. cout << " MyDocument: Close()" << endl;
  33. }
  34. };
  35.  
  36. /* Framework declaration */
  37. class Application
  38. {
  39. public:
  40. Application(): _index(0)
  41. {
  42. cout << "Application: ctor" << endl;
  43. }
  44. /* The client will call this "entry point" of the framework */
  45. NewDocument(char *name)
  46. {
  47. cout << "Application: NewDocument()" << endl;
  48. /* Framework calls the "hole" reserved for client customization */
  49. _docs[_index] = CreateDocument(name);
  50. _docs[_index++]->Open();
  51. }
  52. void OpenDocument(){}
  53. void ReportDocs();
  54. /* Framework declares a "hole" for the client to customize */
  55. virtual Document *CreateDocument(char*) = 0;
  56. private:
  57. int _index;
  58. /* Framework uses Document's base class */
  59. Document *_docs[10];
  60. };
  61.  
  62. void Application::ReportDocs()
  63. {
  64. cout << "Application: ReportDocs()" << endl;
  65. for (int i = 0; i < _index; i++)
  66. cout << " " << _docs[i]->GetName() << endl;
  67. }
  68.  
  69. /* Customization of framework defined by client */
  70. class MyApplication: public Application
  71. {
  72. public:
  73. MyApplication()
  74. {
  75. cout << "MyApplication: ctor" << endl;
  76. }
  77. /* Client defines Framework's "hole" */
  78. Document *CreateDocument(char *fn)
  79. {
  80. cout << " MyApplication: CreateDocument()" << endl;
  81. return new MyDocument(fn);
  82. }
  83. };
  84.  
  85. int main()
  86. {
  87. /* Client's customization of the Framework */
  88. MyApplication myApp;
  89.  
  90. myApp.NewDocument("foo");
  91. myApp.NewDocument("bar");
  92. myApp.ReportDocs();
  93. }

Output

  1. Application: ctor
  2. MyApplication: ctor
  3. Application: NewDocument()
  4. MyApplication: CreateDocument()
  5. MyDocument: Open()
  6. Application: NewDocument()
  7. MyApplication: CreateDocument()
  8. MyDocument: Open()
  9. Application: ReportDocs()
  10. foo
  11. bar

Do you like it? Share on social networks!

f
  • Aug. 9, 2019, 8:48 p.m.
  • (edited)

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

  1. bool NewDocument(char *name)
  2. {
  3. if (_index >= 10) { return false; }
  4. cout << "Application: NewDocument()" << endl;
  5. /* Framework calls the "hole" reserved for client customization */
  6.  
  7. _docs[_index] = CreateDocument(name);
  8. _docs[_index++]->Open();
  9. return true;
  10. }
  11. ~Application()
  12. {
  13. for (int i = _index - 1; i >= 0; --i) {
  14. delete _docs[i];
  15. }
  16. }

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

  1. void DeleteDocument(Document *doc)
  2. {
  3. delete doc;
  4. }

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

  1. ~Application()
  2. {
  3. for (int i = _index - 1; i >= 0; --i) {
  4. DeleteDocument(_docs[i]);
  5. }
  6. }

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

  1. class Document {};
  2.  
  3. class Document1 : public Document {};
  4.  
  5. class Document2 : public Document {};
  6.  
  7. void main() {
  8. const int TYPE1 = 1;
  9. const int TYPE2 = 2;
  10. Document *m[10];
  11. for (int i = 0; i < 10; ++i) {
  12. int type;
  13. cin >> type;
  14. if (type == TYPE1) { m[i] = new Document1(); }
  15. else { m[i] = new Document2(); }
  16. }
  17. // some code
  18. }

Comments

Only authorized users can post comments.
Please, Log in or Sign up
  • Last comments
  • Evgenii Legotckoi
    March 9, 2025, 9:02 p.m.
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    March 9, 2025, 4:14 p.m.
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
  • ИМ
    Nov. 22, 2024, 9:51 p.m.
    Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
  • Evgenii Legotckoi
    Oct. 31, 2024, 11:37 p.m.
    Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
  • A
    Oct. 19, 2024, 5:19 p.m.
    Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html