• C++设计模式-创建型设计模式:抽象工厂


    目录

    抽象工厂介绍-定义、结构、参考实现、场景

    场景

    如何设计

    定义

    本质:选择产品簇的实现,优缺点

    何时选用抽象工厂:强调一系列相关产品接口、联合使用它们的时候

    抽象工厂模式的工程应用-控件式开发


    抽象工厂介绍-定义、结构、参考实现、场景

    场景

    • 完成两套GUI的表示层,一个在PC,另一个在平板、手机上的应用程序界面
    • 通常一个显著的设备差别在于分辨率

    如何设计

    • 从封装的角度来讲,希望根据布局器来配置i我们的控件,我们开放布局器接口控件接口,供客户端调用

    首先来看不使用设计模式的做法:

    1. #include
    2. using namespace std;
    3. class FrameApi {
    4. public:
    5. virtual void draw() = 0;
    6. protected:
    7. FrameApi() {}
    8. };
    9. class LayoutApi {
    10. public:
    11. virtual void installFrame() = 0;
    12. protected:
    13. LayoutApi() {}
    14. };
    15. //PC Frame
    16. class ComputerFrame :public FrameApi {
    17. public:
    18. ComputerFrame(int pins) :m_pins(pins) {}
    19. void draw() {
    20. cout << "现在是PC Frame,分辨率适用:" << m_pins << endl;
    21. }
    22. private:
    23. int m_pins;
    24. };
    25. //Mobile Frame
    26. class MobileFrame :public FrameApi {
    27. public:
    28. MobileFrame(int pins) :m_pins() {}
    29. void draw() {
    30. cout << "现在是Mobile Frame,分辨率适用:" << m_pins << endl;
    31. }
    32. private:
    33. int m_pins;
    34. };
    35. //高分辨率布局
    36. class HighLayout :public LayoutApi {
    37. public:
    38. HighLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
    39. void installFrame() {
    40. cout << "现在是在PC环境下使用高分辨率布局" << m_FrameAdapterPins << endl;
    41. }
    42. private:
    43. int m_FrameAdapterPins;
    44. };
    45. //低分辨率布局
    46. class LowLayout :public LayoutApi {
    47. public:
    48. LowLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
    49. void installFrame() {
    50. cout << "现在是在Mobile环境下使用低分辨率布局" << m_FrameAdapterPins << endl;
    51. }
    52. private:
    53. int m_FrameAdapterPins;
    54. };
    55. //创建产品的简单工厂
    56. class FrameFactory {
    57. public:
    58. static FrameApi* createFrame(int type) {
    59. if (type == 1)return new ComputerFrame(1024);
    60. if (type == 2)return new MobileFrame(800);
    61. return nullptr;
    62. }
    63. };
    64. class LayoutFactory {
    65. public:
    66. static LayoutApi* createLayout(int type) {
    67. if (type == 1)return new HighLayout(1024);
    68. if (type == 2)return new LowLayout(800);
    69. return nullptr;
    70. }
    71. };
    72. class GUIEngineer {
    73. public:
    74. void prepareDraw(int FrameType, int LayoutType) {
    75. this->pFrame = FrameFactory::createFrame(FrameType);
    76. this->pLayout = LayoutFactory::createLayout(LayoutType);
    77. pFrame->draw();
    78. pLayout->installFrame();
    79. }
    80. private:
    81. FrameApi* pFrame;
    82. LayoutApi* pLayout;
    83. };
    84. int main() {
    85. GUIEngineer* pEng = new GUIEngineer;
    86. pEng->prepareDraw(1, 1);
    87. return 0;
    88. }

    这样的作法,应该告诉客户:

    FrameType是用来选择Frame控件的类型

    LayoutType是用来选择布局管理器的类型

    如果客户这么做:

    pEng->prepareDraw(1, 2);
    

    则:

    明显结果不适配。

    为了避免这种结果,我们需要进行类似提取公因式的办法,来解决此类问题,把相像的关系进行提取,避免造成关系不适配的情况。

    这里就引出抽象工厂的概念:

    定义

    • 功能:
      • 为一系列相关对象或相互依赖的对象创建一个接口
      • 从某种意义上看,抽象工厂其实是一个产品系列,或者是产品簇
    • 实现:AbstractFactory为接口
    • 方法:
      • AbstractFactory定义产品所需接口,具体实现在实现类里面。
      • AbstractFactory定义的创建产品的方法可以看成是工厂方法,而这些工厂方法的具体实现就延迟到了具体的工厂里面,也就是说用工厂来实现抽象工厂
    • 切换产品簇:
      • AbstractFactory定义了一个产品簇,因此切换产品簇时提供不同的AbstractFactory就好了

    我们将简单工厂替换为抽象工厂,也就是将产品替换为产品簇:

    1. #include
    2. using namespace std;
    3. class FrameApi {
    4. public:
    5. virtual void draw() = 0;
    6. protected:
    7. FrameApi() {}
    8. };
    9. class LayoutApi {
    10. public:
    11. virtual void installFrame() = 0;
    12. protected:
    13. LayoutApi() {}
    14. };
    15. //PC Frame
    16. class ComputerFrame :public FrameApi {
    17. public:
    18. ComputerFrame(int pins) :m_pins(pins) {}
    19. void draw() {
    20. cout << "现在是PC Frame,分辨率适用:" << m_pins << endl;
    21. }
    22. private:
    23. int m_pins;
    24. };
    25. //Mobile Frame
    26. class MobileFrame :public FrameApi {
    27. public:
    28. MobileFrame(int pins) :m_pins() {}
    29. void draw() {
    30. cout << "现在是Mobile Frame,分辨率适用:" << m_pins << endl;
    31. }
    32. private:
    33. int m_pins;
    34. };
    35. //高分辨率布局
    36. class HighLayout :public LayoutApi {
    37. public:
    38. HighLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
    39. void installFrame() {
    40. cout << "现在是在PC环境下使用高分辨率布局" << m_FrameAdapterPins << endl;
    41. }
    42. private:
    43. int m_FrameAdapterPins;
    44. };
    45. //低分辨率布局
    46. class LowLayout :public LayoutApi {
    47. public:
    48. LowLayout(int FrameAdapterPins) :m_FrameAdapterPins(FrameAdapterPins) {}
    49. void installFrame() {
    50. cout << "现在是在Mobile环境下使用低分辨率布局" << m_FrameAdapterPins << endl;
    51. }
    52. private:
    53. int m_FrameAdapterPins;
    54. };
    55. //AbstractFactory产品簇
    56. class AbstractFactory {
    57. public:
    58. virtual FrameApi* createFrameApi() = 0;
    59. virtual LayoutApi* createLayoutApi() = 0;
    60. protected:
    61. AbstractFactory(){}
    62. };
    63. //产品簇1
    64. class Schemal :public AbstractFactory {
    65. public:
    66. FrameApi* createFrameApi() {
    67. return new ComputerFrame(1024);
    68. }
    69. LayoutApi* createLayoutApi() {
    70. return new HighLayout(1024);
    71. }
    72. };
    73. //产品簇2
    74. class Schema2 :public AbstractFactory {
    75. public:
    76. FrameApi* createFrameApi() {
    77. return new MobileFrame(1024);
    78. }
    79. LayoutApi* createLayoutApi() {
    80. return new LowLayout(1024);
    81. }
    82. };
    83. class AdanvancedGuiEngineer {
    84. public:
    85. void prepareMaterials(AbstractFactory* pSchema) {
    86. this->pFrame = pSchema->createFrameApi();
    87. this->pLayout = pSchema->createLayoutApi();
    88. pFrame->draw();
    89. pLayout->installFrame();
    90. }
    91. private:
    92. FrameApi* pFrame;
    93. LayoutApi* pLayout;
    94. };
    95. int main() {
    96. AdanvancedGuiEngineer* pEng = new AdanvancedGuiEngineer();
    97. pEng->prepareMaterials(new Schemal());
    98. return 0;
    99. }

    Nice!

    其实就相当于:点套餐,这样就不会出现不适配的情况。

    本质:选择产品簇的实现,优缺点

    • 优点:
      • 分离接口和实现
      • 切换产品簇变的容易
    • 缺点:
      • 不太容易扩展新产品
      • 容易造成类层次复杂

    何时选用抽象工厂:强调一系列相关产品接口、联合使用它们的时候

     

    抽象工厂模式的工程应用-控件式开发

    • 业务功能封装成控件
    • 微软有一个叫做asp.net的控件组,他认为对于一个Web应用来说,虽然搜索框、广告条、导航条、页面主题的设计和实现有很大差别,但是绝大多数的Web应用基本布局还是大致相同的。最后都可以组装成一个页面的过程也是大致相同的。
    • 这种具有同一属组的产品簇特别适合用抽象工厂进行装配

     

  • 相关阅读:
    helm简介
    NSS [鹤城杯 2021]Middle magic
    vscode访问远程服务器的图形界面如firefox
    【数据结构初阶】详解 环形链表:链表的带环问题(判断是否带环、环形链表的入口点)
    FL Studio水果最新版2023安装图文详细教程
    html和winform webBrowser控件交互并播放视频(包含转码)
    gym强化学习环境搭建
    一款好用的PDF转翻页电子书网站
    JVM认识之垃圾收集算法
    如何在linux服务器上安装Anaconda与pytorch
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/126110684