名称
抽象工厂模式(ABSTRACT FACTORY),别名:Kit
目的
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用性
在以下情况可以使用Abstract Factory模式
一个系统要独立于它的产品的创建、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
结构
抽象工厂(AbstractFactory):声明一个创建抽象产品对象的操作接口。
具体工厂(ConcreteFactory):实现创建具体产品对象的操作。实现AbstractFactory接口。
抽象产品(AbstractProduct):为一类产品对象声明一个接口。
具体产品(ConcreteProduct):定义一个将被相应的具体工厂创建的产品对象。实现AbstractProduct接口。
客户端(Client):仅使用由AbstractFactory和AbstractProduct类声明的接口。
协作
通常在运行时刻创建一个ConcreteFactroy类的实例。这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工厂。
AbstractFactory将产品对象的创建延迟到它的ConcreteFactory子类。
效果
优点
分离了具体的类。将客户与类的实现分离,客户通过它们的抽象接口操纵实例。产品的类名也在具体工厂的实现中被分离;它们不出现在客户代码中。
易于交换产品系列。一个具体工厂类在一个应用中仅出现一次(初始化时),这使得改变一个应用的具体工厂更加容易,只需改变具体工厂即可使用不同的产品系列。这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系列会立刻改变。
有利于产品的一致性。当一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,抽象工厂很容易实现这一点。
缺点
难以支持新种类的产品。AbstractFactory接口确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及AbstractFactory类及其所有子类的改变
应用
问题
我们在使用浏览器的时候可以设置浏览器的外观(比如下图的谷歌浏览器设置),当切换外观的时候背景、按钮等组件都会有不同的展示。此时我们想要设计一款浏览器,分别有春天和夏天两种外观,当切换外观时,浏览器的按钮、文本框、组合框会有不同的展示,此时外观就对应着我们的抽象工厂,春天和夏天外观对应着具体工厂,按钮、文本框、组合框对应着抽象产品,春天和夏天的按钮、文本框、组合框就是我们的具体产品。
示例
UML
代码示例
抽象工厂:外观工厂接口,定义三个抽象产品的方法createButton、createTextField、createComboBox
package com.ysj.part3.abstractFactory.abstractFactory;
import com.ysj.part3.abstractFactory.abstractProduct.Button;
import com.ysj.part3.abstractFactory.abstractProduct.ComboBox;
import com.ysj.part3.abstractFactory.abstractProduct.TextField;
//界面皮肤工厂接口:抽象工厂
public interface SkinFactory {
public Button createButton();
public TextField createTextField();
public ComboBox createComboBox();
}
抽象产品:按钮、文本框、组合框,定义接口方法display
package com.ysj.part3.abstractFactory.abstractProduct;
//在本实例中我们对代码进行了大量简化,实际使用时,界面组件的初始化代码较为复杂,还需要使用JDK中一些已有类,为了突出核心代码,在此只提供框架代码和演示输出。
//按钮接口:抽象产品
public interface Button {
public void display();
}
package com.ysj.part3.abstractFactory.abstractProduct;
//文本框接口:抽象产品
public interface TextField {
public void display();
}
package com.ysj.part3.abstractFactory.abstractProduct;
//组合框接口:抽象产品
public interface ComboBox {
public void display();
}
具体工厂:春天、夏天外观具体工厂,实现抽象工厂SkinFactory
package com.ysj.part3.abstractFactory.concreteFactory;
import com.ysj.part3.abstractFactory.abstractFactory.SkinFactory;
import com.ysj.part3.abstractFactory.abstractProduct.Button;
import com.ysj.part3.abstractFactory.abstractProduct.ComboBox;
import com.ysj.part3.abstractFactory.abstractProduct.TextField;
import com.ysj.part3.abstractFactory.concreteProduct.SpringButton;
import com.ysj.part3.abstractFactory.concreteProduct.SpringComboBox;
import com.ysj.part3.abstractFactory.concreteProduct.SpringTextField;
//Spring皮肤工厂:具体工厂
public class SpringSkinFactory implements SkinFactory {
public Button createButton() {
return new SpringButton();
}
public TextField createTextField() {
return new SpringTextField();
}
public ComboBox createComboBox() {
return new SpringComboBox();
}
}
package com.ysj.part3.abstractFactory.concreteFactory;
import com.ysj.part3.abstractFactory.concreteProduct.SummerButton;
import com.ysj.part3.abstractFactory.concreteProduct.SummerComboBox;
import com.ysj.part3.abstractFactory.concreteProduct.SummerTextField;
import com.ysj.part3.abstractFactory.abstractFactory.SkinFactory;
import com.ysj.part3.abstractFactory.abstractProduct.Button;
import com.ysj.part3.abstractFactory.abstractProduct.ComboBox;
import com.ysj.part3.abstractFactory.abstractProduct.TextField;
//Summer皮肤工厂:具体工厂
public class SummerSkinFactory implements SkinFactory {
public Button createButton() {
return new SummerButton();
}
public TextField createTextField() {
return new SummerTextField();
}
public ComboBox createComboBox() {
return new SummerComboBox();
}
}
具体产品:春天、夏天外观的具体产品按钮、文本框、组合框,实现各自的抽象产品
package com.ysj.part3.abstractFactory.concreteProduct;
import com.ysj.part3.abstractFactory.abstractProduct.Button;
//Spring按钮类:具体产品
public class SpringButton implements Button {
public void display() {
System.out.println("显示浅绿色按钮。");
}
}
package com.ysj.part3.abstractFactory.concreteProduct;
import com.ysj.part3.abstractFactory.abstractProduct.ComboBox;
//Spring组合框类:具体产品
public class SpringComboBox implements ComboBox {
public void display() {
System.out.println("显示绿色边框组合框。");
}
}
package com.ysj.part3.abstractFactory.concreteProduct;
import com.ysj.part3.abstractFactory.abstractProduct.TextField;
//Spring文本框类:具体产品
public class SpringTextField implements TextField {
public void display() {
System.out.println("显示绿色边框文本框。");
}
}
package com.ysj.part3.abstractFactory.concreteProduct;
import com.ysj.part3.abstractFactory.abstractProduct.Button;
//Summer按钮类:具体产品
public class SummerButton implements Button {
public void display() {
System.out.println("显示浅蓝色按钮。");
}
}
package com.ysj.part3.abstractFactory.concreteProduct;
import com.ysj.part3.abstractFactory.abstractProduct.ComboBox;
//Summer组合框类:具体产品
public class SummerComboBox implements ComboBox {
public void display() {
System.out.println("显示蓝色边框组合框。");
}
}
package com.ysj.part3.abstractFactory.concreteProduct;
import com.ysj.part3.abstractFactory.abstractProduct.TextField;
//Summer文本框类:具体产品
public class SummerTextField implements TextField {
public void display() {
System.out.println("显示蓝色边框文本框。");
}
}
使用到的工具类:从xml中解析内容
package com.ysj.common.utils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class XMLUtil {
//该方法用于从XML配置文件中提取图表类型,并返回类型名
public static String getChartType() {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File(String.class.getResource("/config.xml").getPath()));
//获取包含图表类型的文本节点
NodeList nl = doc.getElementsByTagName("chartType");
Node classNode = nl.item(0).getFirstChild();
String chartType = classNode.getNodeValue().trim();
return chartType;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
public static Object getBean(String className) {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File(String.class.getResource("/config.xml").getPath()));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName(className);
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
xml:config.xml
<?xml version="1.0"?>
<config>
<summerSkin>com.ysj.part3.abstractFactory.concreteFactory.SummerSkinFactory</summerSkin>
<springSkin>com.ysj.part3.abstractFactory.concreteFactory.SpringSkinFactory</springSkin>
</config>
客户端:Client
package com.ysj.part3.abstractFactory;
import com.ysj.common.utils.XMLUtil;
import com.ysj.part3.abstractFactory.abstractFactory.SkinFactory;
import com.ysj.part3.abstractFactory.abstractProduct.Button;
import com.ysj.part3.abstractFactory.abstractProduct.ComboBox;
import com.ysj.part3.abstractFactory.abstractProduct.TextField;
/**
* 抽象工厂模式
* 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
*/
class Client {
public static void main(String args[]) {
//使用抽象层定义
SkinFactory factory;
Button bt;
TextField tf;
ComboBox cb;
factory = (SkinFactory) XMLUtil.getBean("springSkin");
bt = factory.createButton();
tf = factory.createTextField();
cb = factory.createComboBox();
bt.display();
tf.display();
cb.display();
}
}
已知应用
java Swing/AWT
提供了不同的Look and Feel(外观与感觉)抽象工厂,如MetalLookAndFeel, MotifLookAndFeel等,这些工厂负责创建特定风格的GUI组件。
spring Framework
spring的核心是IOC容器,其中BeanFactory 接口是所有IOC容器的基础,它提供了创建和管理 Bean 的通用方法。
评论区