使用抽象工厂解决“根据类名生成类对象”

 

 

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

 

  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 的改进,放弃了抽象工厂模式,去掉了沉重的工厂负担。

                                                                         

posted @ 2018-07-17 00:26  皇家救星  阅读(416)  评论(3编辑  收藏  举报