Java设计模式-创建型设计模式-抽象工厂模式
从这一专栏开始将学习设计模式,上课学习和自己总结归纳的笔记将总结出来供大家参考。
参考书籍:《设计模式就该这样学》
其他文章:
文章目录
一、创建型设计模式
创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对客户端代码需要调用对象的时候隐藏了类的实例化的创建细节。
其中包括:简单工厂模式(不在GoF23种设计模式中)、工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。
二、抽象工厂模式
1.抽象工厂模式定义
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂,在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
在GoF23种设计模式中属于创建型设计模式:
其中包括:简单工厂模式(不在GoF23种设计模式中)、工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。
2.产品等级结构和产品族
(1) 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL 电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
(2) 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。
3.抽象工厂模式的角色
同工厂方法模式一样,抽象工厂模式也是这四个角色
抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
4.抽象工厂模式的特点
优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。
缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。
5.抽象工厂模式的类图
6.抽象工厂模式的代码实现
6.1案例
抽象产品:按钮、文本框、组合框
具体产品:浅绿色的按钮、绿色边框的文本框、绿色边框的组合框、浅蓝色的按钮、蓝色边框的文本框、蓝色边框的组合框
抽象工厂:皮肤工厂
具体工厂:Spring风格工厂、Summer风格工厂
类图如下:
6.2具体代码实现
1.抽象产品(Button)接口和具体产品类(SpringButton、SummerButton)
public interface Button {
void display();
}
public class SpringButton implements Button {
@Override
public void display() {
System.out.println("浅绿色的按钮");
}
}
public class SummerButton implements Button {
@Override
public void display() {
System.out.println("浅蓝色的按钮");
}
}
2.抽象产品(TextField)接口和具体产品类(SpringTextField、SummerTextField)
public interface TextField {
void display();
}
public class SpringTextField implements TextField{
public void display(){
System.out.println("显示绿色边框文本框");
}
}
public class SummerTextField implements TextField{
public void display(){
System.out.println("显示蓝色边框文本框");
}
}
3.抽象产品(ComboBox)接口和具体产品类(SpringComboBox、SummerComboBox)
public interface ComboBox{
void display();
}
public class SpringComboBox implements ComboBox{
public void display(){
System.out.println("显示绿色边框组合框");
}
}
public class SummerComboBox implements ComboBox {
@Override
public void display() {
System.out.println("显示蓝色边框组合框");
}
}
4.抽象工厂(SkinFactory)接口和具体工厂类(SpringSkinFactory、SummerSkinFactory)
public interface SkinFactory {
Button createButton();
TextField createTextField();
ComboBox createComboBox();
}
public class SpringSkinFactory implements SkinFactory{
public Button createButton(){
return new SpringButton();
}
public TextField createTextField(){
return new SpringTextField();
}
public ComboBox createComboBox(){
return new SpringComboBox();
}
}
public class SummerSkinFactory implements SkinFactory{
public Button createButton(){
return new SummerButton();
}
public TextField createTextField(){
return new SummerTextField();
}
public ComboBox createComboBox(){
return new SummerComboBox();
}
}
5.配置文件SkinProperties.properties,在配置文件中存储了具体工厂类的类名。
FactoryClassName=com.abstractfactory.skinfactory.SpringSkinFactory
6.ConfigUtils(读取配置文件工具类)
public class ConfigUtils {
/**
* 从properties文件中创建Bean对象
* @param fileName properties文件名
* @param key 包含的Bean对象的类名的配置项
* @return Bean实例
*/
public static <T>T getBeanFromProp(String fileName,String key) {
try {
Properties pros = new Properties();
InputStream is =ConfigUtils.class.getClassLoader().getResourceAsStream(fileName);
//加载配置文件
pros.load(is);
//通过反射创建Bean实例
Class clazz = Class.forName(pros.getProperty(key));
T bean=(T)clazz.newInstance();
return bean;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
7.Client(客户端测试类)
public class Client {
public static void main(String[] args) {
SkinFactory skinFactory = ConfigUtils.getBeanFromProp("SkinProperties.properties", "FactoryClassName");
Button button = skinFactory.createButton();
ComboBox comboBox = skinFactory.createComboBox();
TextField textField = skinFactory.createTextField();
button.display();
comboBox.display();
textField.display();
}
}
8.测试结果