1. 定义
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。抽象工厂模式又称为Kit 模式,它是一种对象创建型模式。
2. 问题
现有这么一个需求:我们现在要为某软件定制2套皮肤,一套是Spring风格,一个是Summer风格,以后会继续扩展更多的皮肤。对于每种风格的皮肤,我们都需要设计出相应风格的Button、TextFiled等组件。结构示意图如下:
3. 解决方案
如果采用上一篇中讲的工厂方法模式,我们首先需要抽象产品类和工厂类,即抽象出产品类Button和TextFiled类和工厂类ButtonFactory和TextFiledFactory类;然后根据具体的产品,我们需要实现SpringButton、SummerButton、SpringTextFiled、SummerTextFiled和它们对应的工厂SpringButtonFactory、SummerButtonFactory、SpringTextFiledFactory、SummerTextFiledFactory。如果我们需要再扩展其他的皮肤,只需要再给出相应的Button和TextField的实现,并给出相对应的工厂方法。
根据上面的分析,此解决方案看似不错,它满足开闭原则,当增加新的皮肤时,我们不需要再修改现有代码,但实际上它是有缺陷的。一来当增加皮肤时,我们需要增加大量的工厂类;二来在我们的问题中,同一种风格的产品(工厂)是绑定在一起的,即SpringButton和SpringTextField是同时使用的,SummerButton和SummerTextField是同时使用的;而该方案并没有将同种风格的产品(工厂)绑定,这就有可能由于工厂的选择不当而造成界面风格的错乱。
由于工厂方法的这些缺陷,抽象工厂孕育而生。
介绍工厂方法之前,先介绍两个概率:
① 产品等级结构
产品等级结构即产品的继承结构。例如问题中的抽象类Button,其子类有SpringButton,SummerButton,它们属于一个产品等级结构。
② 产品族
在抽象工厂模式中,产品族是指由同一工厂生成的,位于不同产品等级结构的一组产品。如问题中的SpringButton、SpringTextField,它们属于一个产品族。
产品等级结构和产品族的示意图如下:
采用抽象工厂方法,我们将一个产品族中的所有对象作为一个工厂的产品,即一个工厂负责一个产品族所有产品的生产,这样就可以大大减少工厂类(特别是在一个产品族中有多个产品的时候);而且在扩增产品族时,是满足开闭原则的(但是对于产品等级结构的扩充不满足,这种特性被称为开闭原则的倾向性)。
下面是用Java代码给出的具体解决方案:
① 抽象产品和工厂类
Button.java
public abstract class Button { public Button() { System.out.println("初始化Button..."); } protected void setText(String text) { System.out.println("设置Button内的文字..."); } }
TextField.java
public abstract class TextField { public TextField() { System.out.println("初始化TextFiled..."); } protected void setText(String text) { System.out.println("设置TextFiled内的文字..."); } }
Factory.java
public interface Factory { public Button createButton(); public TextField createTextField(); }
② 实现(这里只给出Spring风格的实现)
SpringButton.java
public class SpringButton extends Button { public SpringButton() { super(); System.out.println("初始化SpringButton..."); } }
SpringTextField.java
public class SpringTextField extends TextField{ public SpringTextField() { super(); System.out.println("初始化SpringTextField..."); } }
SpringFactory.java
public class SpringFactory implements Factory { @Override public Button createButton() { return new SpringButton(); } @Override public TextField createTextField() { // TODO Auto-generated method stub return new SpringTextField(); } }
XMLUtil.java
public class XMLUtil { public static Object getBeanFromXml(String beanName) { if (beanName == null || beanName.isEmpty()) { return null; } DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new File("config.xml")); NodeList beansList = document.getElementsByTagName("beans"); if (beansList.getLength() == 0) { return null; } NodeList beanList = beansList.item(0).getChildNodes(); for (int i = 0; i < beanList.getLength(); i++) { if (beanList.item(i).getNodeType() == Node.ELEMENT_NODE) { if (beanName.equals(beanList.item(i).getNodeName())) { return Class.forName(beanList.item(i).getTextContent()).newInstance(); } } } } catch (Exception e) { e.printStackTrace(); } return null; } }
config.xml
<beans> <springFactoryspringFactory>abstractMethod.factory.impl.SpringFactory</springFactory> </beans>
③ 测试
public class App { @Test public void test1() { Factory factory = (Factory) XMLUtil.getBeanFromXml("springFactory"); Button button = factory.createButton(); TextField textField = factory.createTextField(); System.out.println("Spring Style:" + button + textField); } }
结果:
初始化Button...
初始化SpringButton...
初始化TextFiled...
初始化SpringTextField...
Spring Style:abstractMethod.product.impl.SpringButton@5b37e0d2abstractMethod.product.impl.SpringTextField@4459eb14