工厂模式定义了一个用于创建对象的接口,这种模式将对象的创建推迟到子类去完成,从某种程度上实现了OCP原则
以生产汽车轮胎为例, 我们打算生产几种不同品牌的轮胎,有宝马的轮胎,奥迪的轮胎和奔驰汽车的轮胎,由于产品的类型相似,我们可以将他们抽象成轮胎,轮胎就是一个抽象类
那么有些朋友会说,这有什么,我想生产什么我直接写个函数就行了, 比如 create_factory()中直接实现生产宝马,奥迪和奔驰轮胎的代码,打完收工就可以了。首先要说明的一点是,这种思想是没有错的,但是考虑问题太片面了,太理想化了。
首先,生产出来的轮胎是一个对象,对象是要拿来使用的,但是不明确的是,谁要用这个new出来的对象, 如果是客户要用,ok, 宝马客户需要一个轮胎,然后我们把这个生产所有的轮胎的代码交给了宝马,宝马拿来后估计要笑死,因为奥迪和奔驰轮胎的
生成代码也在里面,这是不行的。第二点就是,即使将制造宝马轮胎的代码封装成一个函数交给宝马,这也是不行的,因为宝马并不关心你的轮胎是怎么做出来的,宝马要的是一个轮胎,我们提供接口,仅仅如此。而且这样的编程方式会破坏OCP原则,即宝马的需求一旦变更,
那么伴随着的提交到客户手中的代码也要改变,注意是改变,不是添加,这样的设计也是不太好的。
就像前面所说的,如果我们设计一个工厂类,比如它默认生产宝马轮胎,然后分别创建它的子类,即宝马工厂,奥迪工厂,奔驰工厂,它们分别生产相应的轮胎,这样类的粒度比较适中,耦合度比较低,什么叫耦合我想提一下,耦合其实就是类与类,对象与对象之间的关系紧密程度,
如果很多类很多对象相互依赖,只要其中一个变化,其它的都要跟着变化,这种情况我们就笼统的称为高耦合度,试想,一旦客户需求变化,那么几乎所有的类的实现都要跟着变化,在修改代码时很容易出错,调试也会很艰难。高内聚说的其实也是一样的道理,将类恰到好处的分解,使
它的粒度适中,这种高内聚低耦合就是我们的目标。当然,这样做也是需要付出代价的,但是与维护难度相比,我们仍然趋向于高内聚低耦合。
请看下面的UML图,BMW工厂new出来的是BMW的轮胎,因此这个产品和工厂就是依赖关系,因为最终BMW Factory的成员函数返回的一定是一个BMW Tire类型的指针,客户拿到指针就可以使用了。
为了能更好的说明,我实现了这个工厂模式给大家,代码(包括测试代码)亲测,无须再自己调试, 其中注意的是, Tire Factory在实现当中设计成一个抽象类,这是为了更好的给大家展示多态的威力,实际编码中根据需要,也可以将它设计成一个具体类
代码如下:
#include <iostream>
#include <string>
using namespace std;
class Tire
{
public:
string mark;
virtual void print_mark(void)=0;
virtual ~Tire(){}
};
class BMW_Tire: public Tire
{
public:
BMW_Tire(string car_mark)
{
this->mark = car_mark;
}
virtual void print_mark()
{
cout<<"The mark of the tire in the BMW is: "<<this->mark<<endl;
}
};
class Benz_Tire: public Tire
{
public:
Benz_Tire(string car_mark)
{
this->mark = car_mark;
}
virtual void print_mark()
{
cout<<"The mark of the tire in the Benz is: "<<this->mark<<endl;
}
};
class Audi_Tire: public Tire
{
public:
Audi_Tire(string car_mark)
{
this->mark = car_mark;
}
virtual void print_mark()
{
cout<<"The mark of the tire in the Audi is: "<<this->mark<<endl;
}
};
class Tire_Factory
{
public:
virtual Tire* produce_tire()=0;
virtual ~Tire_Factory(){}
};
class BMW_Factory: public Tire_Factory
{
public:
virtual Tire* produce_tire()
{
return (new BMW_Tire("BMW"));
}
};
class Benz_Factory: public Tire_Factory
{
public:
virtual Tire* produce_tire()
{
return (new Benz_Tire("Benz"));
}
};
class Audi_Factory: public Tire_Factory
{
public:
virtual Tire* produce_tire()
{
return (new Audi_Tire("Audi"));
}
};
//框架
void test(Tire_Factory* tf)
{
Tire* tire_p = tf->produce_tire();
tire_p->print_mark();
}
int main(int argc, char **argv)
{
//Test 1 for BMW
BMW_Factory *bf = new BMW_Factory();
test(bf);
delete bf;
//Test 2 for Benz
Benz_Factory *bef = new Benz_Factory();
test(bef);
delete bef;
//Test 3 for Audi
Audi_Factory *af = new Audi_Factory();
test(af);
delete af;
return 0;
}
观察test会发现,设计这个框架的好处就是,在框架不发生改变的情况下,利用多态实现不同对象的测试,而从客户角度出发,就更方便了,只需要知道类名和测试函数名,
就可以运行框架了,而框架几乎永久不需要改变或者很长时间才发生改变, 比如中国银行的自动提款机,框架几乎就是不变的。还有一个好处就是,当我们是客户,同时有几家竞标时,可以使用框架,
我们只需要提供给这几家工厂我们的类和测试接口,他们把他们的产品放到我们的测试函数中来,运行结果,根据结果我们就会择优选择厂家,达到竞标效果。
仔细体会,这种模式是非常常见和有用的。