1、为什么要使用工厂模式?
首先先看看不使用工厂模式的代码
class MyAPI
{
public:
virtual void MyFunc();
};
class A : public MyAPI
{
void MyFunc()
{
printf("A");
}
};
class B : public MyAPI
{
void MyFunc()
{
printf("B");
}
};
void ClientFunc()
{
MyAPI * a = new A;
MyAPI * b = new B;
a->MyFunc();
b->MyFunc();
}
有何问题?请各位仔细看客户端这段话:
MyAPI * a = new A;
MyAPI * b = new B;
然后再想想接口的功能和思想,发现什么了?仔细再想想?你会发现在客户端调用的时候,客户端不但知道了接口,同时还知道了具体的实现就是A。 接口的思想是“封装 隔离”,而实现类A/B应该是被接口MyApi封装并同客户端隔离开的,也就是说,客户端根本就不应该知道具体的实现类是A/B。有朋友说,那好,我就把A/B从客户端拿掉,让Api真正地对 实现进行“封装 隔离”。可是,新的问题出现了,当他把“ new A()”去掉后,却发现无法得到MyApi接口对象了,怎么办呢?把这个问题描述一下:在面向对象编程中,出现只知接口而不知实现,该怎么办? 就像现在的Client,它知道要使用Api接口,但是不知由谁实现,也不知道如何实现,从而得不到接口对象,就无法使用接口,该怎么办呢?
2、解决方案--是工厂模式:
请看以下代码:
class MyAPI
{
public:
virtual void MyFunc();
};
class A : public MyAPI
{
void MyFunc()
{
printf("A");
}
};
class B : public MyAPI
{
void MyFunc()
{
printf("B");
}
};
class Factory
{
public:
static MyAPI* createInstance(int type)
{
if(0 == type)
{
return new A;
}
else if (1 == type)
{
return new B;
}
else
{
return NULL;
}
}
};
void ClientFunc()
{
MyAPI* a = Factory::createInstance(0);
MyAPI* b = Factory::createInstance(1);
a->MyFunc();
b->MyFunc();
}
就如同上面的示例 ,客户端通过简单工厂创建了一个实现接口的对象 ,然后面向接口编程 ,从客户端来看 ,它根本不知道具体的实现是什么 ,也不知道是如何实现的 ,它只知道通过工厂获得了一个接口对象 ,然后通过这个接口来获取想要的功能 。事实上 ,简单工厂能帮助我们真正地开始面向接口编程 ,像以前的做法 ,其实只是用到了接口的多态部分的功能 ,而最重要的 “封装隔离性 ”并没有体现出来。
3、常见问题:
首先来解决一个常见的问题 :可能有朋友会认为 ,上面示例中的简单工厂看起来不就是把客户端里面的 “new A / new B”移动到简单工厂里面吗 ?不还是一样通过new一个实现类来得到接口吗?把 “new A / new B”这句话放到客户端和放到简单工厂里面有什么不同吗 ?提示理解这个问题的重点就在于理解简单工厂所处的位置 。根据前面的学习 ,我们知道接口是用来封装隔离具体的实现的 ,目标就是不要让客户端知道封装体内部的具体实现 。简单工厂的位置是位于封装体内的 ,也就是简单工厂是跟接口和具体的实现在一起的 ,算是封装体内部的一个类 ,所以简单工厂知道具体的实现类是没有关系的 。
4、工厂模式的优缺点
简单工厂有以下优点 :
■帮助封装简单工厂虽然很简单 ,但是非常友好地帮助我们实现了组件的封装 ,然后让组件外部能真正面向接口编程 。
■解耦通过简单工厂 ,实现了客户端和具体实现类的解耦 。如同上面的例子 ,客户端根本就不知道具体是由谁来实现 ,也不知道具体是如何实现的 ,客户端只是通过工厂获取它需要的接口对象 。
简单工厂有以下缺点 :
■可能增加客户端的复杂度如果通过客户端的参数来选择具体的实现类 ,那么就必须让客户端能理解各个参数所代表的具体功能和含义,各个参数所代表的具体功能和含义 ,这样会增加客户端使用的难度 ,也部分暴露了内部实现 ,这种情况可以选用可配置的方式来实现 。
■不方便扩展子工厂私有化简单工厂的构造方法 ,使用静态方法来创建接口 ,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了 。不过 ,通常情况下是不需要为简单工厂创建子类的 。
陈臣 (2011-01-01). 研磨设计模式 (Kindle Locations 856-860). 清华大学出版社. Kindle Edition.