zoukankan      html  css  js  c++  java
  • 使用抽象工厂解决“根据类名生成类对象”

     

    前段时间参加了一个项目的开发,里面有一个程序需要实现这样的功能:

     

    1. 程序启动时根据命令行参数提供的接口名称调用不同接口

    2. 所有接口相互独立,但能抽象出共同行为work主函数只需负责调用该接口执行work动作

    3. 接口可能经常变化(增删改),但主函数基本不变

      这个程序是这样实现的:

      第一版程序实现(详细见附件中的demo_project_v1):

    1. 定义一个基类,做为所有接口类的父类

    //class_base.h

    class class_base

    {

    public:

            virtual void work() = 0;

            virtual ~class_base();

    };

    1. 每个接口封装成一个独立的类继承自 class_base 并且实现work。

    // classA.h

    class classA :

            public class_base

    {

    public:

            classA(void);

            void work();

            ~classA(void);

    };

    // classB.h

    //与A大致相同

    1. 主函数根据通过if else语句,根据命令行参数决定调用不同类

    //main.cpp

    #include "stdafx.h"

    #include "class_base.h"

    #include "classA.h"

    #include "classB.h"

     

    int main(int argc, char* argv[])

    {

            assert(argc > 1);        string class_name = argv[1];

            class_base *cbase = NULL;

     

            if (class_name == "classA")

            {

                    cbase = new classA();

            }

            else if (class_name == "classB")

            {

                    cbase = new classB();

            }

            else

            {

                    cerr << "error input" << endl;

                    return -1;

            }

     

            cbase->work();

     

            delete cbase;

            return 0;

    }

     

    程序这样实现确实比较方便,但是存在以下问题:

    1. 通过if else来判断需要调用哪个接口类,在类少的时候没啥问题,但是在接口慢慢增多的时候,就会出现某一个类要经过N次判断后才能确定被调用(前面说过,接口是会经常增加的),N随接口个数增加而线性增加

    2. 每次新增类都需要修改main.cpp,增加该类的头文件,并且增加if else分枝,致使main函数越来越长,编译也越来越慢

    3. 修改了接口类的头文件,就需要重新编译main.cpp,当接口类比较多时编译比较慢(指在VS下,如果是自己写Makefile则不会有这个问题)

      但是当时由于时间的关系,这个程序就将就这样了。在之后相对比较有空时间,我开始想,下次碰上这种问题应该怎么解决,但是一直没找到好的解决方法。

            

           直到最近,学习了设计模式,才发现,原来前人早已总结出一个针对这种问题的设计模式。没错,就是标题里的“抽象工厂”模式。

          这里简单介绍一下抽象工厂(百度上找到的)

    意图:

        提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

    适用性:

    一个系统要独立于它的产品的创建、组合和表示时

    一个系统要由多个 产品系列中的一个来配置时

    当你要强调一个系列相关的产品对象的设计以便进行联合使用时

                                                                                       

       简单地说,提供一个创建接口类的接口,而无需指定它们的具体类(即可以不需要知道它们的实现)。下面介绍具体实现

    第二版程序实现(详细见附件中的demo_project_v3

    首先,定义一个抽象工厂(工厂类接口)IFACTORY

    //class_base.h

    class IFACTORY

    {

    public:

        virtual class_base *create_class() = 0;

    public:

        virtual ~IFACTORY(void);

    };

      为每个类实现一个类工厂(继承于抽象工厂)

      //FactoryA.h

    #include "class_base.h"

    class FactoryA :

    public IFACTORY

    {

    public:

            FactoryA(void);

            class_base *create_class();

            ~FactoryA(void);

    };

     

    //FactoryA.cpp

        #include "FactoryA.h"

    #include "classA.h"

    class_base *FactoryA::create_class()

    {

            return new classA();

    }

    这样主函数里面只需要知道类工厂定义即可,无需知道类的定义

    //main.cpp

    #include "stdafx.h"

    #include "class_base.h"

    #include "FactoryA.h"

    #include "FactoryB.h"

     

    int main(int argc, char* argv[])

    {

            assert(argc > 1);

            map<string, IFACTORY*> mpClasses;

            mpClasses["classA"] = new FactoryA();

            mpClasses["classB"] = new FactoryB();

     

            IFACTORY *ClassFactory = mpClasses[argv[1]];

            if (ClassFactory == NULL)

            {

                    cerr << "error input" << endl;

                    return -1;

            }

     

            class_base *cbase = ClassFactory->create_class();

            cbase->work();

            delete cbase;

            return 0;

    }

     

    经过引入抽象工厂后,

        由于不知道接口类的实现,接口类的头文件修改就不会再导致main.cpp重新编译了

        并且,由于使用了map来选择类工厂,比较次数相比以前的if else大大减少

     

           引用抽象工厂后,问题3跟问题1都解决了,但是问题2似乎没解决,新增一个类之后仍然需要修改main.cpp的mpClasses注册一个新的工厂类。

     

           但是,经过观察,我们可以看到,其实每个类工厂都代码基本是一样的,所以,我们可以预先写好多个类工厂(类工厂1,类工厂2),通过配置指定不同字符串对应不同类工厂。当需要新增类时只需要修改一下配置文件,并且修改一个相应类工厂的实现即可。(当然有更好的解决方法,留等读者自己思考) (如果懒得思考可以直接看demo_project_v4的实现)

          

           本文介绍了根据字符串生成类的一种实现方法,实际上还有更多实现方法(如反射)之类,各位读者有兴趣可以上网查。(完)

     

     

     

     

     

    后记:

    demo_project_v3的实现有几个问题

    1  每新增一个类需要copy大量重复无用的代码(类工厂)

    2 增加新类必须修改main.cpp增加新的类工厂(用文章结尾的方法,则需修改配置文件和类工厂)

     

    demo_project_v4是解决这个问题的方案

     

    demo_project_v5 demo_project_v4 的改进,放弃了抽象工厂模式,去掉了沉重的工厂负担。

                                                                             

  • 相关阅读:
    pow()函数结果强制转化为int造成误差的分析
    warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    博客园鼠标点击特效代码
    codeblocks更改颜色主题
    codeblocks1712设置中文
    SQl
    项目中nodejs包高效升级插件npm-check-updates
    正则表达式的整理(将金钱数变成带有千分位)
    从一个数组中过滤出另外一个数组中相关字段相等的数据
    IONIC3 打包安卓apk详细过程(大量图文)
  • 原文地址:https://www.cnblogs.com/kingstarer/p/9321218.html
Copyright © 2011-2022 走看看