工厂模式
模式定义
工厂模式是一个设计模式族,在GOF95中分类为创建型模式:
子模式 | 定义 |
简单工厂 | 只能算是一种代码惯例。将创建某个类层次中对象的代码封装到一个单独的类的一个方法中,这个类就是简单工厂 |
静态工厂 | 简单工厂中,如果方法是静态的,则称为静态工厂。静态工厂失去了多态性 |
工厂方法 | 亦称多态性工厂,该模式定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类 |
抽象工厂 | 该模式定义了提供一个接口,用来创建相关或者依赖的产品族,而不需要明确指定具体类 |
模式结构与说明
Java中新的对象是通过new操作符生成的,一旦使用该操作符,代码必然依赖于具体类,例如下面的代码:
1 2 3 4 |
Person p; if ( en ) p = new English(); else if ( cn ) p = new Chinese(); else if ( jp) p = new Japanese(); |
通过if-else结构决定使用哪个Person运行时实现,意味着每出现一个新的Person子类,就必须修改上面这段代码,这违反了开闭原则。为了隔离创建对象示例的逻辑,我们引入一个工厂对象,原先的代码则变成工厂的客户。工厂模式具有简单工厂、工厂方法、抽象工厂等几种形式。
工厂方法的类图如下(注意工厂Creator中的其它逻辑,例如operation,是工厂方法的客户):
抽象工厂的类图如下(注意Client与模式是组合关系,而工厂方法则是继承关系):
工厂模式的优点:
- 将创建对象的代码集中到一起,避免散在的new操作符,增强软件可维护性
- 帮助实践面向接口编程,客户可以在不知道具体产品实现的情况下编程
- 工厂方法模式很好的体现了依赖倒转原则
- 抽象工厂模式可以用来管理产品族的创建,产品族中的产品是一起被使用的。在增加新的产品族时,只需要引入新的具体工厂角色即可,符合开闭原则
工厂模式的缺点:
- 抽象工厂模式在修改产品族层次结构时,会违反开闭原则
经典应用
Java集合框架生成迭代器
Collection 接口相当于抽象的工厂角色, iterator() 方法用于创建 Iterator ,这是工厂方法的应用。 List 接口的 listIterator() 方法则是创建 listIterator() 的工厂。
COM组件的IClassFactory
IClassFactory、IUnknown、IDispatch是微软COM组件架构的三大核心接口,我们通常使用 CoCreateInstance() 函数来创建COM组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
HRESULT CoCreateInstance( const CLSID& clsid, IUnknown* punkonwnDuter, DWORD dwClsContext, const IID& iid, void** ppv ) { *ppv = NULL; IClassFactory* pIFactory = NULL; //创建工厂:注册表查找clsid得知DLL的位置,装入DLL库,进而通过GetProcAddress得到函数指针,调用得到工厂 HRESULT hr = CoGetClassObject( clsid, dwClsContext, NULL, IID_IClassFactory, ( void** ) &pIFactory ); if ( SUCCEEDED( hr ) ) { //创建对象实例 hr = pIFactory->CreateInstance( punkonwnDuter, iid, ppv ); pIFactory->Release(); } return hr; } |
可以看到, IClassFactory 相当于工厂方法中的抽象工厂角色, CoGetClassObject() 函数通过一系列内部处理,得到具体工厂的角色,然后调用 CreateInstance() 函数创建具体产品角色 IUnknown ,类图如下:
模式演变
- 工厂方法模式,如果去除抽象的工厂角色,那么就变得和简单工厂很类似,可以改为简单工厂来实现
- 抽象工厂模式,如果只需要创建一类产品,则与工厂方法很类似,此时如果去掉抽象的工厂角色,就相当于简单工厂
- 与模板方法模式结合:工厂方法和模板方法都是基于方法的,工厂方法可以作为模板方法模式中的一个扩展点
Leave a Reply