抽象工厂模式的倾斜性和改进设计研究

   1 概述 
  抽象工厂模式源于面向对象设计领域里的经典教材《设计模式》,顾名思义,抽象工厂模式用于系统运行时生产需的对象,是一种创建型模式,在系统设计时是创建对象的核心模式。 
  对于使用抽象工厂模式增加新产品的等级结构,学者们普遍认为必须修改所有的工厂角色,只能以修改源码的方式新增新产品的等级结构,说明抽象工厂模式没有很好支持开闭原则(OCP),以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的产品等级结构的增加提供这样的方便。这种方式也已不能够为制造业信息化和服务化服务,文中给出符合开闭原则的设计方案,同时对抽象工厂的缺点做了改进设计,以适应系统设计时搭建上层框架的需求。 
  2 新增产品等级结构的设计 
  如果已有产品等级A和B,产品族1和2,需增加产品等级结构C可以按图1所示进行 
  图1 新增产品等级结构的设计类图 
  图中新增两大类内容,由虚线标注 
  第一,新增的产品等级结构C位于图下方,由三个类组成AbstractProductC、ProductC1、ProductC2。其中ProductC1、ProductC2都继承于AbstractProductC。 
  第二,工厂,这个是添加产品等级结构最重的部分,由三部分组成接口AbstractFactoryC1、类ConcreteFactoryC1、类ConcreteFactoryC2。 
  下面给出三个工厂的源码 
  工厂接口AbstractFactoryC.java 
  public interface AbstractFactoryC extends AbstractFactory{ 
  AbstractProductC createProductC(); 
  } 
  实现工厂ConcreteFactoryC1.java 
  public class ConcreteFactoryC1 extends ConcreteFactory1 implements AbstractFactoryC{ 
  @Override 
  public AbstractProductC createProductC(){ 
  return new ProductC1(); 
  } 
  } 
  实现工厂ConcreteFactoryC2.java 
  public class ConcreteFactoryC2 extends ConcreteFactory2 implements AbstractFactoryC{ 
  @Override 
  public AbstractProductC createProductC(){ 
  return new ProductC2(); 
  } 
  } 
  第一,新增的工厂接口AbstractFactoryC继承于AbstractFactory,接口AbstractFactoryC内新增了生产产品等级结构C的方法CreateProductC(),返回的类型是产品等级C。 
  第二,新增两个工厂类ConcreteFactoryC1和ConcreteFactoryC2,其中ConcreteFactoryC1继承了ConcreteFactory1类,从上面可以知道,ConcreteFactory生产了产品族A1和B1,因为继承的关系,ConcreteFactoryC1也有了这些功能。并且在类中生产了产品C1,支持了产品族1的生产。同理ConcreteFactoryC2也完成了产品族2的生产功能。
  第三,完成客户端的调用,如下 
  public class Client{ 
  public static void main(Stringargs){ 
  AbstractFactoryC cf1=new ConcreteFactoryC1(); 
  cf1.createProductC(); 
  AbstractFactoryC cf2=new ConcreteFactoryC2(); 
  cf2.createProductC(); 
  } 
  } 
  cf1能够生产对象C1,cf2可以生产对象C2。从这个设计可以看出没有改动图1中任何接口和类的源码,完全符合开闭原则(OCP),对系统内新增功能以新增类和接口方式完成。 
  3 抽象工厂模式改进设计 
  从以上内容可以看出抽象工厂模式并没有在新增产品等级时的所谓倾斜性的问题,但是这种模式还是有一些别的问题。这里需对这些问题进行改进 
  第一,系统需AbstractProduct产品的子类时无法完成任务。在上面的设计中能看出,AbstractFactory依赖AbstractProductA,ConcreteFactory1只负责生产AbstractProductA的子类ProductA,Client调用AbstractFactory后获得AbstractProductA。如果Client需ProductA继承于AbstractProductA后新增的属性或方法,这个模式就无法正常运行,而ProductA中肯定有自己新定义的方法和属性,否则不需新增子类,而且这些方法和属性必定会在系统某个地方使用,那么以工厂类为唯一生产对象的入口设计方案还是需进行改进。改进的方法就是引入泛型。
  第二,新增产品等级结构时工厂一侧的结构不易维护。上面的设计中新增产品等级C必须新加入抽象工厂AbstractFactoryC,再加入实现类ConcreteFactoryC1和ConcreteFactoryC2,产生了三个由继承而来的类,继承过多会造成耦合加剧,不利于维护。而且若新增次数增多则类规模会急速增大,产生很多冗余代码。这个问题的根源在于工厂一侧没有进行抽象设计,仅仅简单地做了方法提取。 
  下面就这两个问题给出详细的改进设计。 
  图2 改进设计类图 
  新增接口IProduct,AbstractProductA和AbstractProductB都继承于它。这样就出现一个产品的基接口。 
  引入泛型,修改AbstractFactory代码如下 
  public interface AbstractFactory

PRODUCT createProduct(); 

新增接口AbstractProductA 
public interface AbstractFactoryA
extends AbstractFactory
{} 
这个接口产生对产品A的泛型依赖,因为还是泛型,子类在实现这个接口时就可以生产出AbstractProductA的子类。 
最后实现工厂ConcreteFactoryA,这里只给出生产A1产品的代码,其余工厂类似,不再一一赘述。 
public class ConcreteFactoryA implements AbstractFactoryA

@Override 
public ProductA1 createProduct(){ 
return new ProductA1(); 


4 结语 
本文通过对生产不同产品族和不同产品等级结构中新增产品等级结构的设计方案验证了抽象工厂模式不必修改源码也可以增加产品等级结构,同时也指出了相关设计时的注意事项,最后对抽象工厂的缺点做了改进 
设计。 
参考文献 
1 Erich Gamma,李英军,等.设计模式可复用面向对象软件的基础M.北京机械工业出版社,2009. 
2 阎宏.Java与模式M.北京电子工业出版社,2002. 
3 王翔.设计模式基于C#的工程化实现及扩展M.北京电子工业出版社,2009. 
(责任编辑周 琼)