序言
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重问题,由于工厂模式中的每个工厂只能生产一类产品,可能会导致大量的工厂类,,势必会增加系统的开销,此时可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来生产。———这也就是抽象工厂的基本思想。
产品等级结构与产品族
在讲抽象工厂模式之前,我们必须明白两个概念: 产品等级结构 、 产品族。
- 产品等级结构: 产品等级结构即产品的继承结构, 如一个抽象类是手游,其子类有腾讯的手游、 网易的手游、 盛大的手游等等。则抽象手游与具体游戏公司的手游构成一个产品等级结构,手游是父类,而其它具体公司的手游则是子类。
- 产品族: 在抽象工厂模式中,产品族是指由同一个工厂生产,位于不同产品等级结构中的一组产品。如腾讯公司生产的手游、端游、页游, 腾讯的手游则位于手游产品等级结构中,腾讯的端游则位于端游产品结构中, 腾讯的手游、 端游、 页游就构成了一个产品族。
我们看到不同的颜色的多个椭圆形、正方形、三角形分别构成了三个不同的产品等级结构,而颜色相同的椭圆、正方形、三角形构成一个产品族,可以看到每一个形状都位于某个产品族,并不属于某个产品等级结构,图中有4个产品族,分属于3个不同的产品等级结构。只要知道一个产品的所处的产品族和产品等级结构,就可以确定这个产品。
抽象工厂模式
定义:提供一个创建一系列相关或相互依赖的接口,而无需指定它们具体的类。抽象工厂模式又称为Kit模式,它也是一种对象创建型模式
在抽象工厂模式有一下几个角色:
- AbstractProduct(抽象产品):为每种产品声明接口,在抽象产品中声明了产品所有的业务接口。
- ConcrteProduct(具体产品) : 定义具体的工厂生产的具体产品对象,实现了抽象产品的所有方法。
- AbstractFactory(抽象工厂):声明了创建一组用于创建一族产品的接口,每个方法对应一种产品。
- ConcreteFactory(具体工厂):实现了抽象工厂中所有的接口,这些接口返回的产品构成了一个产品族,每个产品都位于某个产品等级结构中。
代码实现:
AbstractProduct(抽象产品)
/**
* @program
* @Desc 抽象 产品A
* @Author 游戏人日常
* @CreateTime 2019/07/15--18:56
*/
public abstract class AbstractProductA {
}
/**
* @program
* @Desc 抽象 产品B
* @Author 游戏人日常
* @CreateTime 2019/07/15--18:57
*/
public abstract class AbstractProductB {
}
ConcreteProduct(具体产品) : 产品A和产品B构成产品族, A1和A2构成产品等级结构。
/**
* @program
* @Desc 具体的产品 A1
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:04
*/
public class ConcreteProductA1 extends AbstractProductA{
}
/**
* @program
* @Desc 具体的产品 B1
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:04
*/
public class ConcreteProductB1 extends AbstractProductB{
}
/**
* @program
* @Desc 具体的产品 A2
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:03
*/
public class ConcreteProductA2 extends AbstractProductA{
}
/**
* @program
* @Desc 具体的产品 B2
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:07
*/
public class ConcreteProductB2 extends AbstractProductB {
}
AbstractFactory(抽象工厂)
/**
* @program
* @Desc 抽象工厂
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:16
*/
public abstract class AbstractFactory {
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
ConcreteFactory(具体工厂)
/**
* @program
* @Desc 具体工厂 1
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:20
*/
public class ConcreteFactory1 extends AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
/**
* @program
* @Desc 具体工厂 2
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:21
*/
public class ConcreteFactory2 extends AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
客户端测试:
/**
* @program
* @Desc
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:25
*/
public class Test {
public static void main(String args[]){
//声明一个工厂1 就可以生产 A1和B1
AbstractFactory factory1= new ConcreteFactory1();
AbstractProductA productA1=factory1.createProductA();
AbstractProductB productB1=factory1.createProductB();
//声明一个工厂2 就可以生产 A2和B2
AbstractFactory factory2= new ConcreteFactory2();
AbstractProductA productA2=factory2.createProductA();
AbstractProductB productB2=factory2.createProductB();
}
}
“开闭原则”的倾斜性
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构就很麻烦,抽象工厂模式的这种性质称为**“开闭原则“的倾斜性**
- 增加产品族: 对于增加新的产品族,只需要增加个具体的产品并对应增加个具体工厂,对已有的代码不用修改,符合”开闭原则“。
- 增加新的产品等级结构: 对于增加新的产品等级结构,就需要修改工厂角色,包括抽象工厂,需要增加新产品的方法,相应的具体工厂也要改。 违背了”开闭原则“
”增加产品族“ 代码如下:
新增的产品族:
/**
* @program
* @Desc
* @Author 游戏人日常
* @CreateTime 2019/07/15--20:33
*/
public class ConcreteProductA3 extends AbstractProductA {
}
/**
* @program
* @Desc
* @Author 游戏人日常
* @CreateTime 2019/07/15--20:33
*/
public class ConcreteProductB3 extends AbstractProductB {
}
新增具体的工厂类
/**
* @program
* @Desc
* @Author 游戏人日常
* @CreateTime 2019/07/15--20:34
*/
public class ConcreteFactory3 extends AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA3();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB3();
}
}
客户端测试:
/**
* @program
* @Desc
* @Author 游戏人日常
* @CreateTime 2019/07/15--19:25
*/
public class Test {
public static void main(String args[]){
//声明一个工厂1 就可以生产 A1和B1
AbstractFactory factory1= new ConcreteFactory1();
AbstractProductA productA1=factory1.createProductA();
AbstractProductB productB1=factory1.createProductB();
//声明一个工厂1 就可以生产 A2和B2
AbstractFactory factory2= new ConcreteFactory2();
AbstractProductA productA2=factory2.createProductA();
AbstractProductB productB2=factory2.createProductB();
//(新增) 声明一个工厂3 就可以生产 A3和B3
AbstractFactory factory3= new ConcreteFactory3();
AbstractProductA productA3=factory2.createProductA();
AbstractProductB productB3=factory2.createProductB();
}
}
总结
抽象工厂模式是工厂方法模式的进一步延申,继承了工厂方法模式的优点,也弥补了工厂方法模式的一些缺点。 工厂方法模式针对的是一个产品等级结构,而抽象工厂模式是面对多个产品等级结构。
抽象工厂模式增加产品族方便,无需修改代码,只需增加具体的产品类和具体工厂类,符合”开闭原则“。 增加产品等级结构就需要改工厂类(抽象和具体的工厂都改)
抽象模式优缺点
优点
- 抽象工厂模式隔离了具体类的生成,使得客户端并不需要知道什么被创建,由于这种隔离,更换一个具体工厂相对容易些。
- 当一个产品族中的多个对象被设计成一起工作时,这样能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的产品族很方便,无需修改已有代码,符合“开闭原则”。
缺点
- 增加新的产品等级结构麻烦,需要对原来的系统有较大的修改,还会修改抽象层代码,这不符合”开闭原则“
适用场景
- 一个系统不应当依赖于产品实例如何被创建、组合和表达的细节,这对于所有的工厂模式都是很重要,用户无需关系对象的创建过程,将对象的创建与使用解耦。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来,同一产品族的产品可以是没有任何关系,但是它们都具有一些共同的约束
- 产品等级结构稳定,设计完成后,不会向系统中增加新的产品等级结构。