Evgenii Legotckoi
24 сентября 2018 г. 18:23

Пример - Фабричный метод на C++

Содержание

Обсуждение. Фреймфорки представляют собой приложения (или подсистемы) с «местами расширений» в них. Каждый такой фреймворк определяет инфраструктуру, надстройку и поток управления для своей области деятельности, а клиент фреймворка может: осуществлять поведение структуры по умолчанию «как есть», расширить выделенные фрагменты структуры или заменить выбранные фрагменты.

В шаблоне Factory Method рассматривается понятие «создание» в контексте фреймворков. В этом примере структура знает, КОГДА должен быть создан новый документ, а не КАКОЙ это документ. «Заполнитель» Application::CreateDocument() был объявлен фреймворком, и клиент должен «заполнить пробел» для своего ;конкретного документа(ов). Затем, когда клиент запрашивает Application::NewDocument(), фреймворк впоследствии вызывает метод 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. }

Вывод

  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

Вам это нравится? Поделитесь в социальных сетях!

f
  • 9 августа 2019 г. 20:48
  • (ред.)

У метода 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. }

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь