👈️上一篇:工厂方法模式 | 下一篇:建造者模式👉️
目录
- 抽象工厂模式
- 前言
- 概览
- 定义
- 英文原话
- 直译
- 什么意思呢?(以运动型车族工厂,生产汽车、摩托产品为例)
- 类图
- 4个角色
- 抽象工厂(Abstract Factory)角色
- 具体工厂(Concrete Factory)角色
- 抽象产品(Abstract Product)角色
- 具体产品(Concrete Product)角色
- 代码说明
- 1. 抽象工厂类:AbstractFactory.java 接口类
- 2. 具体工厂类:
- 2.1 产品族1的具体工厂类:ConcreteFactoryFamily1.java
- 2.2 产品族2的具体工厂类:ConcreteFactoryFamily2.java
- 3. 抽象产品A类:ProductA.java
- 4. A类产品具体产品类:
- 4.1 产品族为1的A具体产品类:ProductA1.java
- 4.2 产品族为2的A具体产品类:ProductA2.java
- 5. 抽象产品B类:ProductB.java
- 6. B类产品具体产品类:
- 6.1 产品族为1的B具体产品类:ProductB1.java
- 6.2 产品族为2的B具体产品类:ProductB2.java
- 7. 测试类
- 应用
- 优点
- 缺点
- 情景思考,加深理解:
- 使用场景
抽象工厂模式
前言
当一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。(多个产品族1,2,3,产品族4… ,每个产品族都有A、B、C等等产品),
如果产品族中只有一种产品,则抽象工厂模式就退化为工厂方法模式
和上一篇【设计模式深度剖析】【2】【创建型】【工厂方法模式】 对比理解,加深理解:
上一篇【设计模式深度剖析】【2】【创建型】【工厂方法模式】中提到:
工厂方法模式只能针对一个产品等级结构如A产品B产品。
但是如果是A产品与B产品的第一等级、第二等级,这种情况要抽象工厂模式。
也就是它(抽象工厂模式)解决的问题是:多个产品族,多种产品。
多个产品族,每个产品族下又有多种产品——使用抽象工厂模式;
而,仅仅生产某种产品——使用工厂方法模式。
抽象工厂模式(Abstract Factory Pattern)是一种比较常用的模式。
抽象工厂模式是工厂方法模式的升级版本。在有多个业务品种、业务分类时,
通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
======== 本文代码示例 ========
概览
- 定义
- 4个角色
- 应用
- 优点
- 缺点
- 使用场景
定义
英文原话
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
直译
意思是:提供一个接口,用于创建相关或依赖的对象族,而无需指定它们的具体类。
什么意思呢?(以运动型车族工厂,生产汽车、摩托产品为例)
这句话描述了一个设计模式的概念,特别是抽象工厂模式(Abstract Factory Pattern)。抽象工厂模式是一种创建型设计模式,它提供了一种方式来封装一组具有共同主题的单独的工厂接口,而无需指定它们的具体类。
简单来说,假设你有两个或更多的产品族(例如,汽车和摩托车),并且每个产品族中都有多种类型的对象(例如,汽车有跑车、SUV等;摩托车有越野车、街车等)。
你可能想要一个系统,该系统能够基于一些配置或条件来生成这些产品,但你不希望直接依赖于具体的实现类。
抽象工厂模式允许你定义一个接口(抽象工厂),该接口中包含了创建多个产品的方法(每个方法对应于一个产品族中的一个产品类型)。然后,你可以为每种产品族实现这个抽象工厂接口,从而创建具体的产品对象。
以下是一个简化的抽象工厂模式的例子:
// 抽象工厂接口-车辆工厂,能生产两种产品-汽车和摩托
public interface VehicleFactory {
Car createCar();
Motorcycle createMotorcycle();
}
// 抽象产品接口-汽车接口
public interface Car {
// ... Car specific methods
}
// 抽象产品接口-摩托接口
public interface Motorcycle {
// ... Motorcycle specific methods
}
// 具体的产品类(例如,其中一个产品族-运动型车辆族:运动型车辆和运动型摩托车)
// ... 省略具体实现
// 具体工厂类 - 对应于一个产品族,运动型车辆,可以生产运动型汽车、运动型摩托车
public class SportsCarFactory implements VehicleFactory {
@Override
public Car createCar() {
return new SportsCar(); // 假设这是具体的运动型汽车
}
@Override
public Motorcycle createMotorcycle() {
return new SportsMotorcycle(); // 假设这是具体的运动型摩托车
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
VehicleFactory factory = new SportsCarFactory();
Car car = factory.createCar();
Motorcycle motorcycle = factory.createMotorcycle();
// ... 使用car和motorcycle
}
}
在这个例子中,
VehicleFactory
是一个抽象工厂接口,它定义了两个方法(createCar
和 createMotorcycle
)来创建产品。
SportsCarFactory
是一个具体工厂类**(用于同一产品族[运动型族]的不同类型产品[汽车、摩托车])**,它实现了 VehicleFactory
(抽象工厂) 接口,并提供了具体的产品实现(SportsCar
和 SportsMotorcycle
)。
客户端代码使用 SportsCarFactory
来创建和使用 Car
和 Motorcycle
对象,而无需直接依赖于具体的实现类。
类图
4个角色
4个角色与工厂方法模式类似:
抽象工厂(Abstract Factory)角色
该角色是抽象工厂模式的核心,与应用系统无关,任何创建对象的工厂类必须实现这个接口。
具体工厂(Concrete Factory)角色
该角色实现了抽象工厂接口,含有选择合适的产品对象的逻辑,并且受到应用程序的调用以创建产品对象。
抽象产品(Abstract Product)角色
该角色负责定义产品的共性,实现对产品最抽象的定义。
具体产品(Concrete Product)角色
该角色实现抽象产品角色所声明的接口**,抽象工厂模式所创建的任何产品对象都是某个具体产品角色的实例。
代码说明
代码示例
1. 抽象工厂类:AbstractFactory.java 接口类
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 抽象工厂接口:声明有两种产品A与B,定义工厂方法,返回产品A与B
*
* @author Polaris 2024/5/16
*/
public interface AbstractFactory {
//创建产品A
ProductA factoryA();
//创建产品B
ProductB factoryB();
}
2. 具体工厂类:
2.1 产品族1的具体工厂类:ConcreteFactoryFamily1.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 具体工厂类1:实现了抽象工厂接口,生产产品族为1的A产品与B产品。
*
* @author Polaris 2024/5/16
*/
public class ConcreteFactoryFamily1 implements AbstractFactory {
//创建产品族为1的产品A
@Override
public ProductA factoryA() {
return new ProductA1();
}
//创建产品族为1的产品B
@Override
public ProductB factoryB() {
return new ProductB1();
}
}
2.2 产品族2的具体工厂类:ConcreteFactoryFamily2.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 具体工厂类2:实现了抽象工厂接口,生产产品族为2的A产品与B产品。
*
* @author Polaris 2024/5/16
*/
public class ConcreteFactoryFamily2 implements AbstractFactory {
//创建产品族为2的产品A
@Override
public ProductA factoryA() {
return new ProductA2();
}
//创建产品族为2的产品B
@Override
public ProductB factoryB() {
return new ProductB2();
}
}
3. 抽象产品A类:ProductA.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 抽象产品A:抽象产品接口,声明了产品A的方法名称、返回类型
*
* @author Polaris 2024/5/16
*/
public interface ProductA {
//产品A的公共方法
void method1();
void method2();
}
4. A类产品具体产品类:
4.1 产品族为1的A具体产品类:ProductA1.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 具体产品A1:实现了抽象产品A接口
* 产品族为1的A产品
*
* @author Polaris 2024/5/16
*/
public class ProductA1 implements ProductA {
@Override
public void method1() {
System.out.println("产品族为1的产品A的实现方法");
}
@Override
public void method2() {
//业务逻辑代码
}
}
4.2 产品族为2的A具体产品类:ProductA2.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 具体产品A2:实现了抽象产品A接口
* 产品族为2的A产品
*
* @author Polaris 2024/5/16
*/
public class ProductA2 implements ProductA {
@Override
public void method1() {
System.out.println("等级为2的产品A的实现方法");
}
@Override
public void method2() {
//业务逻辑代码
}
}
5. 抽象产品B类:ProductB.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 抽象产品B:抽象产品接口,声明了产品B的方法名称、返回类型
*
* @author Polaris 2024/5/16
*/
public interface ProductB {
//产品B的公共方法
void method1();
void method2();
}
6. B类产品具体产品类:
6.1 产品族为1的B具体产品类:ProductB1.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 具体产品B1:实现了抽象产品B接口
* 产品族为1的B产品
*
* @author Polaris 2024/5/16
*/
public class ProductB1 implements ProductB {
@Override
public void method1() {
System.out.println("等级为1的产品B的实现方法");
}
@Override
public void method2() {
//业务逻辑代码
}
}
6.2 产品族为2的B具体产品类:ProductB2.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 具体产品B2:实现了抽象产品B接口
* 产品族为2的B产品
*
* @author Polaris 2024/5/16
*/
public class ProductB2 implements ProductB {
@Override
public void method1() {
System.out.println("等级为2的产品B的实现方法");
}
@Override
public void method2() {
//业务逻辑代码
}
}
7. 测试类
抽象工厂类,规定了要生产A产品和B产品(接口就是用来定标准,规范标准的,具体到这里就是规定用来生产A产品和B产品)至于怎么生产,由具体工厂类去实现;
它的引用指向一个具体工厂类-生产产品族为1的具体工厂类的实例;
该产品族工厂-具体工厂,可以生产A和B产品,即1族的A与B产品,即A1, B1产品
生产出的A1, A2实例可以执行业务逻辑,
同理,生产产品族为2的产品A和产品B,即A2, B2,也是一样的。
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;
/**
* 测试类
* @author Polaris 2024/5/16
*/
public class ClientDemo {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactoryFamily1();
//生产产品族为1的产品A
ProductA a1 = factory1.factoryA();
//生产产品族为1的产品B
ProductB b1 = factory1.factoryB();
//执行业务逻辑
a1.method1();
b1.method1();
AbstractFactory factory2 = new ConcreteFactoryFamily2();
//生产产品族为2的产品A
ProductA a2 = factory2.factoryA();
//生产等级为1的产品B
ProductB b2 = factory2.factoryB();
//执行业务逻辑
a2.method1();
b2.method1();
}
}
应用
优点
抽象工厂模式是工厂方法模式的进一步抽象,针对的是一族产品。如果产品族中只有一种产品,则抽象工厂模式就退化为工厂方法模式。除了工厂方法模式的优点外,抽象工厂模式还具有下列优点。
- 产品族内的约束为非公开状态,在不同的工厂中,各种产品可能具有不同的相互依赖关系,这些依赖关系由工厂封装在其内部,对于工厂的使用者是不可见的。
- 生产线的扩展非常容易,如果要针对同一产品族建立新的生产线,只需要 实现 产品族中的所有产品接口 并 建立新的工厂类即可。
- ProductA与ProductB就是产品族(类),即A族产品与B族产品;
- ProductA1与ProductA2(或ProductB1与ProductB2)就是A族产品(或B族产品)产品族下不同产品线
- 如A类产品再加一条产品线(族)生产ProductA3(产品族为3的A产品),则需要ProductA3实现ProductA接口方法 ,由于抽象工厂已经定义了A组产品的约束(生产A产品对象的方法),所以对抽象工厂无需改动;但是,每条产品线的产品都需要一个具体工厂类创建对象,因此需要添加一个具体工厂(ConcreteFactoryFamily3)生产新增加的产品线产品A3
缺点
抽象工厂模式的最大缺点就是产品族本身的扩展非常困难,如果需要在产品族中增加一个新的产品类型,则需要修改多个接口,并且会影响已有的工厂类。
* 抽象工厂声明的方法针对所有产品族产品;
* 新增加一个产品族(C类产品),抽象工厂需要添加生产新产品族产品的接口(声明方法);
* 具体工厂是要实现抽象工厂所有接口的,所以相应的具体工厂(所有各个产品线)需要修改(实现创建新增C产品族产品的方法)
情景思考,加深理解:
- 比如此示例:两个产品族(即2个种类产品),两条产品线(分别生产1等级与2等级产品)
- 若:仅仅增加一个产品C(现有产品线都生产这个新增产品类型):
- 创建产品族C接口,并增加C1/C2产品类实现C类接口
- 抽象工厂添加创建此类型产品的接口;
- 所有产品线(具体工厂,某一族)都增加实现接口的方法;
- 若:现在增加一个产品(即增加1个新产品类型C),但是只生产最高等级(即产品线只有一条(产品线1,产品族1)来生产此产品族产品C),该怎么办?
- 抽象工厂抽象了各类产品的生产,其他产品线(生产某一族产品)也要实现该族产品生产的接口(方法),但是,不需要创建出相应对象(产品)(因为其余产品线不生产新增产品族产品),可以抛出异常
- 若:新增产品C,且单独用额外的产品线3生产此族产品(即新产品类型,新开辟产品线专门只用于生产此族产品),该怎么弄?
- 如上个问题,新增产品族,抽象工厂必定添加接口方法用于生产此产品,现有产品线都要实现这个接口(但是根据需求生产不出来,抛出异常);
- 新开辟的产品线由于抽象工厂的约束,它要实现生产所有产品族(包括新增产品族)的接口,这条产品线只需要生产新增产品族,生产其他已有产品族产品时抛出异常即可。
- 所以,新增产品族比较麻烦,涉及到新增产品C接口及具体产品线产品,以及抽象工厂、具体工厂的变动,这是个很大的变动。即:产品族本身的扩展非常困难
使用场景
抽象工厂模式的使用场景是:当一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。
抽象工厂模式是一个简单的模式,使用的场景非常多,
例如,应用需要涉及不同操作系统的时候,可以考虑使用抽象工厂模式,如果需要在三个不同的平台(Windows、Linux、Android)上运行,则可以通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。
👈️上一篇:工厂方法模式 | 下一篇:建造者模式👉️