适用环境:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是用药的。用户无须关心对象的创建过程,将对象的创建和使用解耦。系统有多于一个产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。属于同一个产品族的产品将一起使用,这一约束必须在系统的设计中体现出来。应用:很多系统软件中需要更换界面主题,要求界面的按钮/文本框/背景颜色发生改变时
产品等级结构:电视机、海尔电视机、海信电视机
产品族:海尔电视机、海尔冰箱
当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,二十多个位于不同产品等级结构中属于不同类型的具体产品是需要使用抽象工厂模式。
抽象工厂模式和工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式 。
模式结构图:
代码:
客户端:
package com.abstractfactory.hing; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub OSFactory win = (OSFactory)XMLUtil.getBean(); Button wb = win.produceButton(); wb.show(); OSFactory lin = new LinuxFactory(); Form f = lin.produceForm(); f.show(); } }
抽象产品类
package com.abstractfactory.hing; public interface Button { public void show(); }
具体产品类:
package com.abstractfactory.hing; public class WindowsButton implements Button { public void show() { System.out.println("Windows 按钮就是好看!"); } }
抽象工厂类:
package com.abstractfactory.hing; public interface OSFactory { public Button produceButton(); public Form produceForm(); }
具体工厂类:
package com.abstractfactory.hing; public class WindowsFactory implements OSFactory{ @Override public Button produceButton() { return new WindowsButton(); } @Override public Form produceForm() { return new WindowsForm(); } }
工具类:
package com.abstractfactory.hing; import java.io.File; import javax.xml.parsers.*; import org.w3c.dom.*; public class XMLUtil { public static Object getBean() { try { //创建DOM文档对象 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dfactory.newDocumentBuilder(); Document doc = builder.parse(new File("config.xml")); //获取结点 NodeList nl =doc.getElementsByTagName("className"); Node n = nl.item(0).getFirstChild(); String cName = n.getNodeValue(); System.out.println(cName); Class c = Class.forName(cName); Object obj = c.newInstance(); return obj; }catch(Exception e) { e.printStackTrace(); } return null; } }
config.xml:
<?xml version="1.0" encoding="UTF-8"?> <confg> <className>com.abstractfactory.hing.LinuxFactory</className> </confg>
该模式的难点在于对抽象工厂和抽象产品之间关系的理解,其中两个概念:产品等级结构,产品族的理解也是关键。
问题解决:在上一篇文章中,遇到了不能通过类名来生成对象的尴尬问题,本次也遇到了,通过上网搜索,最后在StackOverflow中找到了解决答案,原来是在使用Class.forName()时,其中的从参数应该写完全(包括所在包),在这里我的className节点中的内容是 LinuxFactory 导致了如下问题:
修改:改成className结点内容改为:com.abstractfactory.hing.LinuxFactory;问题得以解决