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


    之前提到了简单工厂模式,其核心思想是客户端与接口完全解耦。

    而工厂模式是对简单工厂的进一步提炼与总结。

    工厂模式的介绍-定义、结构、参考实现、场景

    场景

    • 实现一个导出数据的应用框架,来让客户选择数据导出的方式,并真正执行数据导出
    • 通常这种系统,在导出数据上会与一些与约定的方式,比如导出为csv格式,数据库备份形式,excel格式,XML格式等

    从封装的角度来讲,我们希望导出的数据数据的业务功能创建ExportFileApi的具体实例,目前只知道接口,该怎么办?

    答:让子类决定实例化某一个类,实现类的实例化的延迟。

    工厂模式图大致如下:

    话不多说,先上代码,注意看注释:

    1. #include
    2. #include
    3. using namespace std;
    4. class ExportFileApi {
    5. public:
    6. virtual bool exportData(string data) = 0;
    7. protected:
    8. ExportFileApi() {}
    9. };
    10. //具体化子类
    11. class ExportTextFile :public ExportFileApi {
    12. public:
    13. bool exportData(string data) {
    14. cout << "正在导出数据" << data << "到csv文件" << endl;
    15. return true;
    16. }
    17. };
    18. //生成数据到数据库
    19. class ExportDB :public ExportFileApi {
    20. public:
    21. bool exportData(string data) {
    22. cout << "正在导出数据" << data << "数据库" << endl;
    23. return true;
    24. }
    25. };
    26. //实现一个ExportOperate,导出数据的业务功能
    27. //这也是接口,具体的工作交给子类实现
    28. class ExportOperate {
    29. public:
    30. bool exportData(string data) {
    31. ExportFileApi* pApi = factoryMethod();
    32. return pApi->exportData(data);
    33. }
    34. protected:
    35. virtual ExportFileApi* factoryMethod() = 0;
    36. };
    37. //具体的实现对象,完成导出工作
    38. class ExportTextFileOperate :public ExportOperate {
    39. //不想让外部来访问
    40. protected:
    41. ExportFileApi* factoryMethod() {
    42. return new ExportTextFile();
    43. }
    44. };
    45. class ExportDBOperate :public ExportOperate {
    46. protected:
    47. ExportFileApi* feactoryMethod() {
    48. return new ExportDB;
    49. }
    50. };
    51. int main() {
    52. ExportOperate* pOperate = new ExportTextFileOperate();
    53. pOperate->exportData("666");
    54. return 0;
    55. }

     对于此例的UML工厂模式的UML:

    定义

    1. 功能:工厂主要功能是让父类不知道具体实现的情况下,完成自身的功能调用,而具体的实现延迟到子类来实现。
    2. 实现:抽象类。工厂中通常父类是一个抽象类,里面包含创建所需对象的抽象方法,这些方法就是工厂方法;也可以实现为一个具体的类,这种情况通常父类中提供获取所需对象的默认实现方法,这样就算没有具体的子类也能够运行。
    3. 参数和返回值:参数——决定到底选用哪一种具体的实现;返回值——一般是被创建对象的接口对象,也可以是抽象类或者一个具体的类的实例

    工厂模式的应用案例与思考-IOC/DI(依赖注入,控制反转)

    依赖注入:应用程序依赖容器创建并注入它所需要的外部资源

    控制反转:容器控制应用程序,由容器反向的向Application注入程序所需要的

    降低A和B的耦合,交由IOC容器去管理。

    同时这种思想适用于很多个对象之间的管理,就比如一个老师要管理50甚至上百个学生,需要一个点名册,记录学号等信息,来管理学生。这个点名册就是IOC。

    具体看一个例子:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. template <class T>
    8. class IocContainer {
    9. public:
    10. IocContainer() {}
    11. ~IocContainer()
    12. {
    13. }
    14. //注册需要创建对象的构造函数,通过一个唯一的标识,以便于以后查找
    15. template<class Drived>
    16. void RegisterType(string strKey) {
    17. std::functionfunction = [] {return new Drived(); };
    18. RegisterType(strKey, function);
    19. }
    20. //根据唯一的标识查找对应的构造函数
    21. T* Resolve(string strKey) {
    22. if (m_createMap.find(strKey) == m_createMap.end()) {
    23. return nullptr;
    24. }
    25. std::functionfunction = m_createMap[strKey];
    26. return function();
    27. }
    28. //创建智能指针
    29. std::shared_ptrResolveShared(string strKey) {
    30. T* ptr = Resolve(strKey);
    31. return std::shared_ptr(ptr);
    32. }
    33. private:
    34. void RegisterType(string strKey, std::functioncreator) {
    35. if (m_createMap.find(strKey) != m_createMap.end()) {
    36. throw std::invalid_argument("已经存在这个key了");
    37. }
    38. m_createMap.emplace(strKey, creator);
    39. }
    40. private:
    41. map>m_createMap;
    42. };
    43. struct ICar {
    44. virtual ~ICar() {}
    45. virtual void test()const = 0;
    46. };
    47. struct Bus:ICar
    48. {
    49. Bus() {}
    50. void test()const { cout << "Bus test" << endl; }
    51. };
    52. struct Track :ICar
    53. {
    54. Track() {}
    55. void test()const { cout << "Track test" << endl; }
    56. };
    57. int main() {
    58. IocContainercarIOC;
    59. carIOC.RegisterType("bus");
    60. carIOC.RegisterType("track");
    61. std::shared_ptrbus = carIOC.ResolveShared("bus");
    62. bus->test();
    63. std::shared_ptrtrack = carIOC.ResolveShared("track");
    64. track->test();
    65. return 0;
    66. }

    工厂模式的本质-依赖倒置-让子类选择实现

    • 依赖倒置原则:要依赖抽象,不要依赖于具体类,不能让高层组件依赖于底层组件,而且不管高层组件还是底层组件,都应该依赖于抽象

    何时选用工厂模式?

    • 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类去实现
    • 如果一个类本身就希望由它的子类来创建所需的对象时候,就应该使用工厂模式。

  • 相关阅读:
    3DEXPERIENCE许可管理流程:高效、合规、易行的软件许可方案
    Harmony Next 文件命令操作(发送、读取、媒体文件查询)
    组件之父子传值
    XML配置文件
    1 opencv-python图像读写模块
    vue预览PDF文件的几种方法
    直线模组怎么搭配电机?
    c++day6---9.13
    node后端接收pdf接口
    P1441 砝码称重 (状压
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/126109558