抽象工厂模式
概念
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象
两个重要概念
产品等级结构
产品的等级结构即产品的继承结构,例如一个抽象类是电冰箱,其子类包括海尔电冰箱,海信电冰箱,TCL电冰箱等,抽象冰箱与具体品牌的冰箱构成了产品等级结构
产品族
同一个工厂生产的位于不同产品等级结构中的一组产品,例如海尔电器生产的海尔电视机,海尔电冰箱,海尔空调等,这些海尔产品构成了一个产品族
角色
- 抽象工厂: 它声明了一组用于创建一族产品的方法,每一个方法对于一种产品
- 具体工厂: 他实现了在抽象工厂中什么的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族
- 抽象产品: 它为每种产品什么接口,即产品等级结构中的抽象接口
- 具体产品: 定义具体工厂生产的具体产品对象,实现抽象产品中声明的业务接口
UML图如下
简单工厂模式的优缺点
优点
- 隔离了具体类的生产,更换一个具体的工厂变得相对容易
- 保证客户端始终只使用同一个产品族中的对象
- 增加新产品族方便,符合开闭原则
缺点
新增产品等级结构麻烦,需要对原有系统做大量的修改,甚至需要改抽象层代码
补充
前面一直说开闭原则,到底什么是开闭原则
开闭原则要求系统对扩展开放,对修改关闭。
适合环境
- 一个系统不应当依赖于产品类的实例如何被创建等细节,无需关心对象创建过程
- 系统中有多个产品族,每次只使用其中一个产品族
- 产品等级结构稳定,不会向系统中新增心得产品等级结构或者删除已有的产品等级结构
例子
现需要开发一套皮肤库,用户可以通过菜单选择不同皮肤,不同的皮肤提供不同视觉效果的按钮,文本框,组合框等元素。例如春天(Spring)风格的浅绿色按钮、文本框。组合框,而夏天(Summer)风格的淡蓝色按钮、文本框、组合框等
分析
我们先将实体与简单工厂的角色一一对应
- 抽象工厂: SkinFactory
- 具体工厂: SpringSkinFactory、SummerSkinFactory
- 抽象产品: Button、TextField、ComboBox
- 具体产品: SpringButton、SpringTextField、SpringComboBox、SummerButton、SummerTextField、SummerComboBox
看不懂不要紧,我们先看UML图,在看代码应该就能理解了
编码
Button.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:20 PM 2019/7/26
* @Description: 按钮接口,充当抽象产品
*/
public interface Button {
void dispaly();
}
SpringButton.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:21 PM 2019/7/26
* @Description: spring按钮类,充当具体的产品
*/
public class SpringButton implements Button {
@Override
public void dispaly() {
System.out.println("显示浅绿色按钮");
}
}
SummerButton.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:22 PM 2019/7/26
* @Description: summer按钮类,充当具体产品
*/
public class SummerButton implements Button {
@Override
public void dispaly() {
System.out.println("显示浅蓝色按钮");
}
}
ComboBox.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:25 PM 2019/7/26
* @Description: 组合框接口,充当抽象产品
*/
public interface ComboBox {
void display();
}
SpringComboBox.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:26 PM 2019/7/26
* @Description: spring类型组合框,充当具体产品
*/
public class SpringComboBox implements ComboBox {
@Override
public void display() {
System.out.println("显示绿色边框组合框");
}
}
SummerComboBox.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:26 PM 2019/7/26
* @Description: summer组合框类,充当具体产品
*/
public class SummerComboBox implements ComboBox{
@Override
public void display() {
System.out.println("显示蓝色边框组合框");
}
}
TextField.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:23 PM 2019/7/26
* @Description: 文本框接口,充当抽象产品
*/
public interface TextField {
void display();
}
SpringTextField.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:23 PM 2019/7/26
* @Description: spring文本框类,充当具体产品
*/
public class SpringTextField implements TextField {
@Override
public void display() {
System.out.println("显示绿色边框文本框");
}
}
SummerTextField.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:24 PM 2019/7/26
* @Description: summer文本框类,充当具体产品
*/
public class SummerTextField implements TextField {
@Override
public void display() {
System.out.println("显示蓝色边框文本框");
}
}
SkinFactory.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:27 PM 2019/7/26
* @Description: 界面皮肤工厂接口,充当抽象工厂
*/
public interface SkinFactory {
Button createButton();
TextField createTextField();
ComboBox createComboBox();
}
SpringSkinFactory.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:28 PM 2019/7/26
* @Description: spring皮肤工厂,充当具体工厂
*/
public class SpringSkinFactory implements SkinFactory {
@Override
public Button createButton() {
return new SpringButton();
}
@Override
public TextField createTextField() {
return new SpringTextField();
}
@Override
public ComboBox createComboBox() {
return new SpringComboBox();
}
}
SummerSkinFactory.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:30 PM 2019/7/26
* @Description: summer皮肤工厂,充当具体工厂
*/
public class SummerSkinFactory implements SkinFactory {
@Override
public Button createButton() {
return new SummerButton();
}
@Override
public TextField createTextField() {
return new SummerTextField();
}
@Override
public ComboBox createComboBox() {
return new SummerComboBox();
}
}
config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<className>cn.kevinlu98.abstractfactory.SummerSkinFactory</className>
</config>
XMLUtil.java
package cn.kevinlu98.abstractfactory;
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;
/**
* @Author: Kevin·Lu
* @Date: 9:17 PM 2019/7/25
* @Description: 读取xml文件中的字符串参数
*/
public class XMLUtil {
public static Object getBean() {
try {
//创建dom文档对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("src/cn/kevinlu98/abstractfactory/config.xml"));
//获取包含类名的文本节点
NodeList nl = document.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String name = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(name);
Object object = c.newInstance();
return object;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Client.java
package cn.kevinlu98.abstractfactory;
/**
* @Author: Kevin·Lu
* @Date: 11:33 PM 2019/7/26
* @Description: 抽象工厂模式,客户端测试类
*/
public class Client {
public static void main(String[] args) {
SkinFactory factory = (SkinFactory) XMLUtil.getBean();
Button button = factory.createButton();
TextField textField = factory.createTextField();
ComboBox comboBox = factory.createComboBox();
button.dispaly();
textField.display();
comboBox.display();
}
}
运行结果
至此,工厂方法设计模式介绍完成,希望能帮助到您