工作几年后,每个程序员都会积累一定的编程经验,编程能力都会得到不同的提升。但是随着时间的推移,你会慢慢地发现,程序开发已经不仅仅是代码的简单堆砌,而是要开始考虑代码的复用扩展,性能优化,高效设计和执行效率等等问题了。为了要应付这些问题,设计模式应运而生。
概念:
简单工厂模式属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式。它实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
例子:
一个鲜活简单的例子总能让人轻松地理解晦涩的概念。我们来看看一个关于汽车价格的简单工厂模式。
我们知道,汽车的品牌和质量,决定了它的价格。就像宝马(BMW),法拉利(Ferrali)和奔驰(Benz)三辆汽车,它们的价格肯定是不一样的。那我们如果想要知道它的价格的话,可以询问销售人员等等。但是在计算机里,我们可不能直接问销售人员啊!
对于它们来说,虽然各自价格不同,但是获取价格却是一种公共操作,是不同的算法,根据面向对象方法,应该要封装变化。于是,
可以创建一个抽象父类车类(Car),声明一个获取价格virtual GetPrice函数的接口。然后创建三个类:BMW,Ferrali和Benz,分别继承于Car。通过继承关系,每个子类可以改写父类的GetPrice函数,从而获取自身的汽车价格。
那么根据简单工厂模式的,我们需要一个工厂类,它根据传入的汽车编号,动态决定应该创建哪一款汽车的实例。汽车编号我们在客户端中传入即可,无需进行对象实例的创建,因为所有创建对象实例的操作都放在工厂类中。这样,以后增加其他品牌的汽车时,也只需增加一个汽车类,并且在工厂类中修改对象创建,对其它的汽车类代码没影响,保证了代码的灵活扩展。
UML图:
通过上面UML图可以看出,Car就是一个抽象汽车产品类,BMW,Ferrali和Benz就是具体汽车产品类。
代码:
#include <iostream>
using namespace std;
class Car
{
public:
float m_fPrice;
public:
virtual float GetPrice()
{
return m_fPrice*1;
}
};
class BMW:public Car
{
public:
float GetPrice()
{
return m_fPrice*3;
}
};
class Ferrali:public Car
{
public:
float GetPrice()
{
return m_fPrice*11;
}
};
class Benz:public Car
{
public:
float GetPrice()
{
return m_fPrice*6;
}
};
class PriceFactory
{
public:
int m_iFlag;
public:
Car* CreateCarPrice(int iFlag)
{
float fPrice=0.0;
Car* car = new Car;
switch (iFlag)
{
case 1:
return(new BMW);
break;
case 2:
return(new Ferrali);
break;
case 3:
return(new Benz);
break;
default:
return(new Car);
break;
}
}
};
int main()
{
float fPrice=0.0;
int iTag=0;
PriceFactory priceFactory;
Car* car;
cout<<"----简单工厂模式开始----"<<endl;
cout<<"BMW:1,Ferrali:2,Benz:3"<<endl;
cout<<"请输入您想要查询的汽车价格:";
cin>>iTag;
car = priceFactory.CreateCarPrice(iTag);
car->m_fPrice = 10000.0;
fPrice = car->GetPrice();
delete car;
car = NULL;
cout<<"价格为:"<<fPrice<<endl;
cout<<"----简单工厂模式结束----"<<endl;
return 1;
}
发散:
客户端中主要是把工厂类返回的汽车子类的实例赋给父类Car,从而实现调用相应子类的GetPrice函数,实现覆盖父类的虚函数GetPrice。
我们知道实现C++的多态有三种方法:函数重载,模板函数和虚函数。虚函数实现的多态称为动态多态,上面代码有以下特点:
1、子类的对象转换给父类的对象如car = priceFactory.CreateCarPrice(iTag);,我们称为向上转型。它是安全的,自动完成,并且会丢失子类型的信息;
2、为了解决子类型信息丢失的问题(子类对象转换给父类),父类必须实现了一个虚函数GetPrice;
3、子类有完全相同的GetPrice函数,覆盖重写父类的虚函数GetPrice,这样便能实现动态多态了(否则只能用指针或引用了)。
优点:
工厂类是整个模式的关键,,它根据客户端传入的汽车代码,决定究竟应该创建哪个汽车类的对象。通过使用工厂类,客户端可以从直接创建具体汽车对象的尴尬局面摆脱出来,仅仅需要确定生成什么汽车对象就可以了,而不必管这些对象究竟如何创建及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。
不足:
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。
使用场景:
1、工厂类负责创建的对象比较少;
2、客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;
3、由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。