设计模式(一):简单工厂模式
最近在看设计模式方面的一些的内容,发现自己以前在面向对象编程方面的能力真的是太水了,实在是还有很多东西需要学习,从这篇文章开始会将所学到的设计模式写下来,也会附上自己的理解以及相关实验代码。
首先来讲讲简单工厂模式,试着想象我们平时生活中的工厂,一个工厂通常都是只有同一种类的产品,比如说鞋子,于是这个工厂里就会生产各种不同的鞋子,像皮鞋、帆布鞋、板鞋、跑步鞋等等。客户需要某种鞋子,当然不会自己生产,肯定是让工厂生产,然后客户去取货。那么客户就要告诉工厂需要哪种鞋子,工厂生产出来给客户就行了。这就是简单工厂模式的思想,通过专门定义一个工厂类来负责创建其他类的实例,被创建的实例通常都具有共同的基类。简单工厂模式中包含的角色及其相应的职责如下:
- 工厂角色:这是简单工厂模式的核心,由它负责创建所有的类的内部逻辑。当然工厂类必须能够被外界调用,创建所需要的产品对象。
- 抽象产品角色:简单工厂模式所创建的所有对象的父类。注意,这里的父类可以是接口也可以是抽象类,它负责描述所有实例所共有的公共接口。
- 具体产品角色:简单工厂所创建的具体实例对象,这些具体的产品往往都拥有共同的父类。
在这里以一个简单的计算器为例,实现加法和减法的运算功能,想想平时我们在真实的计算器上是怎么操作的,比如要求“3+5=?”,我们先按下“3”,然后按下“+”,接着按下“5”,最后按下等号求得结果,这个过程用控制台实现应该就下面这个样子的:
这个例子很简单,任何一个学过C语言的人都能在一个主函数里写几行代码实现这个功能,那么现在用简单工厂模式该怎么实现这个计算器呢?我们这么来设计:
这个例子中的工厂所生产的产品从抽象角度来说是“运算”,因此首先要有一个基类——COperation运算类,该类里有一个虚函数GetResult( )用来实现运算并返回结果。加法运算和减法运算是具体的产品,是运算类的子类,分别对应CAdd类和CSub类,它们各自的GetResult( )具体实现了加法和减法的运算。然后是工厂类CalculationFactory,这个类中定义一个静态函数Create( ),该函数根据客户想要的运算类型,创建该运算类型所对应的具体对象并返回给客户,然后把客户输入的两个操作数给这个运算对象就能得到相应的运算结果。因此在客户端所进行的操作是这样的:
首先输入第一个操作数firstNum、运算符oper('+'或'-')和第二个操作数secondNum,然后通过指针定义一个COperation类型的对象op,表明op所指对象代表的是一种运算,而CalculationFactory类的Create( )函数根据参数oper来产生一个具体的运算对象,并将这个对象的指针赋给op,这样op就是一个指向具体运算对象的指针了:
COperation* op = CalculationFactory::Create(oper);
之后通过设置器把两个操作数传给这个运算对象后,调用其GetResult( )函数就能得到客户想要的运算结果:
op->GetResult()
我们把用简单工厂模式完成的计算器和用C语言面向过程方法实现的计算器做个比较,看看简单工厂模式的优点有哪些。假设现在要添加乘除两种运算,那么只需要添加两个新的子类即可;或者加运算需要修改,那么只要改动加运算子类,也就是无论修改或增删都不影响其他子类,利于程序的维护。而将对象的创建交给工厂实现,客户就无需操心这点,只需将想要的运算对象告诉工厂即可。现在这个计算器是以控制台的形式展现的,那么如果要做成好看的窗口界面,或是在移动设备上实现,只需修改客户端代码或加入其他用于显示界面的类即可,而不影响运算类以及工厂类。
总的来说,简单工厂模式的有点如下:工厂类是整个模式的关键,包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了,而不必管这些对象究竟如何创建及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。
这个模式当然也有缺点,要增加新的运算,在工厂类中就要增加相应的语句使其能够创建新的运算对象,这不符合开放封闭原则。此外,由于工厂类集中了所有实例的创建逻辑,这就直接导致一旦这个工厂出了问题,所有的客户端都会受到牵连,这违反了高内聚责任分配原则。
总的来说,简单工厂模式分离了产品的创建者和消费者,有利于软件系统结构的优化,但工厂类也带了一些缺点。因此,当程序不太复杂,工厂类负责创建的对象比较少,客户只知道传入工厂类的参数,对于如何创建对象不关心时,选用简单工厂模式是一种可行的选择。
最后附上各个类及客户端代码:
class COperation//运算基类 { public: COperation():mFirst(0), mSecond(0)//构造函数 { } virtual ~COperation() { } virtual double GetResult()//基类运算方法 { return 0; } int GetFirst()//第一个数的访问器 { return mFirst; } int GetSecond()//第二个数的访问器 { return mSecond; } void SetFirst(int _first)//第一个数的设置器 { mFirst = _first; } void SetSecond(int _second)//第二个数的设置器 { mSecond = _second; } private: int mFirst;//第一个数 int mSecond;//第二个数 }; class CAdd :public COperation//加法类 { public: double GetResult()//加法运算 { return GetFirst() + GetSecond(); } }; class CSub :public COperation//减法类 { public: double GetResult()//减法运算 { return GetFirst() - GetSecond(); } }; class CalculationFactory//工厂类 { public: static COperation* Create(char _operator)//根据运算符产生运算对象 { COperation *oper;//COperation类型的指针 switch(_operator) { case '+': oper = new CAdd();//指向加法运算对象 break; case '-': oper = new CSub();//指向减法运算对象 break; default: oper = new CAdd();//默认加法运算对象 break; } return oper; } }; int main()//主函数(客户端) { int firstNum, secondNum; char oper; cout << "Please input first number:" << endl; cin >> firstNum; cout << "Please input operator:" << endl; cin >> oper; cout << "Please input second number:" << endl; cin >> secondNum; COperation* op = CalculationFactory::Create(oper); op->SetFirst(firstNum); op->SetSecond(secondNum); cout << "The result is: " << op->GetResult() << endl; delete op; return 0; }