抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
1.1 意图
-
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
为了更清晰地理解工厂方法模式,需要先引入两个概念:
- 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
- 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
-
当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
-
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
-
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
1.2 模式定义
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
1.3 模式结构
抽象工厂模式包含如下角色:
- AbstractFactory:抽象工厂
- ConcreteFactory:具体工厂
- AbstractProduct:抽象产品
- Product:具体产品
1.4 时序图
1.5 代码demo
两个产品:Shape,Color。
步骤1:创建Shape,Color接口和实例:
package DesignPattern23.AbstractFactory;
/**
* Description:工厂方法模式产品接口
* Author:
* Date:
*/
public interface Shape {
void draw();
}
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date:
*/
public interface Color {
void fill();
}
package DesignPattern23.AbstractFactory;
/**
* Description:产品实现类
* Author:
* Date: 2019/11/5
*/
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("draw Rectangle");
}
}
package DesignPattern23.AbstractFactory;
/**
* Description:产品实现类
* Author:
* Date: 2019/11/5
*/
public class Square implements Shape {
@Override
public void draw() {
System.out.println("draw Square");
}
}
package DesignPattern23.AbstractFactory;
/**
* Description:产品实现类
* Author:
* Date: 2019/11/5
*/
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("draw Circle");
}
}
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date: 2019/11/6
*/
public class Red implements Color{
@Override
public void fill() {
System.out.println("color is : red");
}
}
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date: 2019/11/6
*/
public class Green implements Color{
@Override
public void fill() {
System.out.println("color is :Green");
}
}
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date: 2019/11/6
*/
public class Blue implements Color{
@Override
public void fill() {
System.out.println("color is :blue");
}
}
步骤2:创建抽象工厂:
package DesignPattern23.AbstractFactory;
/**
* Description:接口,用于实现子类工厂
* Author:
* Date:
*/
public abstract class AbstractFactory {
public abstract Shape newShape(String shapeType);
public abstract Color newColor(String colorType);
}
步骤3:创建抽象工厂实现:
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date: 2019/11/6
*/
public class ShapeFactory extends AbstractFactory{
@Override
public Shape newShape(String shapeType) {
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color newColor(String colorType) {
return null;
}
}
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date: 2019/11/6
*/
public class ColorFactory extends AbstractFactory{
@Override
public Shape newShape(String shapeType) {
return null;
}
@Override
public Color newColor(String colorType) {
if(colorType == null){
return null;
}
if(colorType.equalsIgnoreCase("RED")){
return new Red();
} else if(colorType.equalsIgnoreCase("GREEN")){
return new Green();
} else if(colorType.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
步骤4:创建 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
package DesignPattern23.AbstractFactory;
/**
* Description:
* Author:
* Date: 2019/11/6
*/
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
步骤5:testDemo:
package DesignPattern23.AbstractFactory;
/**
* Description:测试入口
* Author:
* Date: 2019/11/5
*/
public class TestDemo {
public static void main(String[] args) {
//获取形状工厂
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
//获取形状为 Circle 的对象
Shape shape1 = shapeFactory.newShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取形状为 Rectangle 的对象
Shape shape2 = shapeFactory.newShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取形状为 Square 的对象
Shape shape3 = shapeFactory.newShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
//获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
//获取颜色为 Red 的对象
Color color1 = colorFactory.newColor("RED");
//调用 Red 的 fill 方法
color1.fill();
//获取颜色为 Green 的对象
Color color2 = colorFactory.newColor("Green");
//调用 Green 的 fill 方法
color2.fill();
//获取颜色为 Blue 的对象
Color color3 = colorFactory.newColor("BLUE");
//调用 Blue 的 fill 方法
color3.fill();
}
}
步骤6:执行程序,输出结果:
draw Circle
draw Rectangle
draw Square
color is : red
color is :Green
color is :blue
Process finished with exit code 0
“开闭原则”的倾斜性
-
“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
- 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
- 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
- 抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。
1.6 实例
1.7 总结
- 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
- 抽象工厂模式包含四个角色:抽象工厂用于声明生成抽象产品的方法;具体工厂实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中;抽象产品为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法;具体产品定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。
- 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
- 抽象工厂模式的主要优点是隔离了具体类的生成,使得客户并不需要知道什么被创建,而且每次可以通过具体工厂类创建一个产品族中的多个对象,增加或者替换产品族比较方便,增加新的具体工厂和产品族很方便;主要缺点在于增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。
- 抽象工厂模式适用情况包括:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一起使用;系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。