上回《大话设计模式C++版——简单工厂模式》中指出了简单工厂模式的缺陷,即违背了开发—封闭原则,其主要原因是由于switch的判断结构的使用,使修改或添加新的对象时需要改动简单工厂类的代码,如何改造switch结构,表驱动法就可以粉墨登场了。

表驱动法的介绍见《数据驱动编程之表驱动法》。

1、面向接口编程,先改造抽象接口类IOperation

class IOperation
{
public:
IOperation() : m_nNuml(0), m_nNumr(0) {}
virtual ~IOperation() {} virtual void SetNum(int nNuml = 0, int nNumr = 0)
{
m_nNuml = nNuml;
m_nNumr = nNumr;
} virtual int CalculateResult() = 0; public:
typedef IOperation* (CALLBACK* fn_CreateObject)(); protected:
int m_nNuml, m_nNumr;
};

接口基本无改动,由于表驱动法中需要在表中填入驱动函数接口,故先定义一个该接口函数的定义,用于产生具体接口对象。

2、改造接口对象类

class COperation_Add : public IOperation
{
public:
int CalculateResult()
{
return m_nNuml + m_nNumr;
} static IOperation* CALLBACK CreateObject()
{
return new COperation_Add();
}
}; class COperation_Dec : public IOperation
{
public:
int CalculateResult()
{
return m_nNuml - m_nNumr;
} static IOperation* CALLBACK CreateObject()
{
return new COperation_Dec();
}
};

增加了CreateObject()静态函数,改函数的作用是用来产生本对象。由于表驱动函数是用于回调的,所以需要定义为静态回调函数。

3、改造工厂类,增加驱动表改造switch结构(重点)

class CClassFactory
{
public:
CClassFactory() {}
virtual ~CClassFactory() {} BOOL AddOperationFunc(char cOperation, IOperation::fn_CreateObject func)
{
if (func)
{
m_mapOperationFunc[cOperation] = func;
return TRUE;
} return FALSE;
} IOperation* CreateObject(char cOperation)
{
IOperation::fn_CreateObject func = m_mapOperationFunc[cOperation]; if (func)
{
return func();
} return NULL;
} protected:
std::map<char, IOperation::fn_CreateObject> m_mapOperationFunc; //用map实现驱动表
};

工厂类中的switch消失了,换成了在map中以操作符为key找对应驱动函数,然后进行调用。同时增加了添加新操作符和对应驱动函数的接口AddOperationFunc(),这样如果需要新增加对象或者修改操作符对应的驱动函数,调用此接口即可,灵活性大大增加。

4、使用示例

void	Test()
{
CClassFactory oCClassFactory;
IOperation* poIOperation = NULL; //添加对象工厂的生产对象
oCClassFactory.AddOperationFunc('+', COperation_Add::CreateObject);
oCClassFactory.AddOperationFunc('-', COperation_Dec::CreateObject); poIOperation = oCClassFactory.CreateObject('+'); if (poIOperation)
{
poIOperation->SetNum(2, 3);
printf("2 + 3 = %d\n", poIOperation->CalculateResult()); delete poIOperation;
} poIOperation = oCClassFactory.CreateObject('-'); if (poIOperation)
{
poIOperation->SetNum(2, 3);
printf("2 + 3 = %d\n", poIOperation->CalculateResult()); delete poIOperation;
}
}

使用前需添加操作符和对应的驱动函数,这样一来将用户的任务加重了,而且需要用户认识的类增加了,封装性降低了。是否可进一步改进?

5、进一步改进简单工厂类,提高封装性

class CNewClassFactory : CClassFactory
{
public:
virtual ~CNewClassFactory() {} virtual void Init()
{
AddOperationFunc('+', COperation_Add::CreateObject);
AddOperationFunc('-', COperation_Dec::CreateObject);
}
};

新简单工厂类中,增加了一个初始化函数Init(),代替用户的进行操作符和对应的驱动函数,这样用户只需要调用Init()函数即可,封装性进一步提高,那么有同学可能会问,如果要增加新的计算对象,还不得改动Init()函数代码,这不跑了一圈又回到没改造前的原点了。

这就得用到开放—封闭原则了,新简单工厂类CNewClassFactory中,我们将Init()函数申明为虚函数了,如果我们要增加新的计算对象,可以有2个途径:

5.1用户在自己代码中调用AddOperationFunc()函数进行添加。

5.2继承新简单工厂类,重写Init()函数。

大话设计模式C++版——表驱动法改造简单工厂的更多相关文章

  1. 大话设计模式C++实现-第1章-简单工厂模式

    一.UML图 二.包括的角色 简单工厂模式包括三个角色: (1)工厂类Factory:工厂类是用来制造产品的. 因此,在Factory中有一个用于制造产品的Create函数或者Generate函数之类 ...

  2. 大话设计模式C++版——简单工厂模式

    简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类——依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class I ...

  3. 大话设计模式C++版——工厂模式在COM中的典型应用

    上篇<大话设计模式C++版——抽象工厂模式>中,我们拯救世界未遂,留下小小的遗憾,本篇中我们将给出一个解决方案——COM组件技术,同时也顺便扯扯工厂模式在COM组件技术中的应用. 工厂模式 ...

  4. 大话设计模式C++版——抽象工厂模式

    前面说过,简单工厂模式是最基础的一种设计模式,那以工厂命名的设计模式就是23种设计模式中最多的一种,他们一脉相承,一步一步进化而来,这里就是其中的最后一种——抽象工厂模式(Abstract Facto ...

  5. 大话设计模式C++版——代理模式

    本篇开始前先发个福利,程杰的<大话设计模式>一书高清电子版(带目录)已上传至CSDN,免积分下载. 下载地址:http://download.csdn.net/detail/gufeng9 ...

  6. 大话设计模式C++版——工厂方法模式

    工厂方法模式是以简单工厂模式为基础的,如果未了解简单工厂模式的同学可先浏览<大话设计模式C++版——简单工厂模式>.在简单工厂模式中,提到过简单工厂模式的缺陷,即违背了开发—封闭原则,其主 ...

  7. Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】

    原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part3-factory/ Design ...

  8. 设计模式在cocos2d-x中的使用--简单工厂模式(Simple Factory)

    什么是简单工厂模式? 从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式.通过专门定义一个类来负责创建其它类的实例,被创建的实例 ...

  9. 大话设计模式C++版——原则和引言

    转贴请注明转自:http://blog.csdn.net/gufeng99/article/details/45832711 读程杰的<大话设计模式>有一段时间了,将其C#版的设计模式代码 ...

随机推荐

  1. java1.8的默认方法的坑

    默认方法: 接口的方法一直都是抽象方法,自从1.8出来了之后,新增了一个默认方法.可以在接口中实现方法 1.默认方法需要用default修饰 2.默认方法不能是静态的 3.子接口继承了2个相同签名的默 ...

  2. Nodejs与ES6系列4:ES6中的类

    ES6中的类 4.1.class基本语法 在之前的javascript语法中是不存在class这样的概念,如果要通过构造函数生成一个新对象代码 function Shape(width,height) ...

  3. BitcoinJS - 支持比特币交易的 JavaScript 库

    BitcoinJS 是一个干净,可读的 JavaScript 开发库,用于比特币交易.支持 Node.js 平台和浏览器端.已有超过150万的钱包用户在使用, BitcoinJS 是几乎所有的 Web ...

  4. 灵感来自 Google & YouTube 的苗条的进度栏效果

    NProgress.js 是纳米级的进度条插件.拥有逼真的的涓涓细流动画效果来告诉你的用户,某些事情正在发生.它的灵感来自于谷歌,YouTube,应用了,这款苗条的进度条是完美的,适用于 Turbol ...

  5. 使用 HTML5 WebGL 实现逼真的云朵效果

    这里给大家展示一个使用 HTML5 WebGL 实现超逼真的云朵效果.WebGL 是一项在网页浏览器呈现3D画面的技术,有别于过去需要安装浏览器插件,通过 WebGL 的技术,只需要编写网页代码即可实 ...

  6. 用Phaser来制作一个html5游戏——flappy bird (一)

    Phaser是一个简单易用且功能强大的html5游戏框架,利用它可以很轻松的开发出一个html5游戏.在这篇文章中我就教大家如何用Phaser来制作一个前段时间很火爆的游戏:Flappy Bird,希 ...

  7. js 内存小记

    其实不知道怎么起这篇blog的题目了 其实只要涉及的内容是内存泄漏的问题,也有内存管理的一些知识,把学习的过程拿来分享 垃圾回收机制 js具有自动的垃圾收集机制,它会找出那些不在继续使用的变量然后释放 ...

  8. Number()、parseInt() 和 parseFloat() 的区别

    一:Number() 如果是Boolean值,true和false值将分别被转换为1和0. 如果是数字值,只是简单的传入和返回. 如果是null值,返回0. 如果是undefined,返回NaN. 如 ...

  9. 对比MS Test与NUnit Test框架

    前言: 项目中进行Unit Test时,肯定会用到框架,因为这样能够更快捷.方便的进行测试. .Net环境下的测试框架非常多,在这里只是对MS Test和NUnit Test进行一下比较, 因为这两个 ...

  10. AppCompatActivity实现全屏的问题

    前言:我的 Activity 是继承 BaseActivity , 而 BaseActivity 继承 AppCompatActivity . BaseActivity 的继承 /** * 应用程序的 ...