5.抽象工厂模式
概念
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。抽象工厂又称为Kit模式,属于对象创建型模式。
抽象工厂可以将统一产品族的单独工厂封装起来,在正常使用中,客户端需要创建抽象工厂的实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。
用途
抽象工厂模式和工厂模式一样,都符合开放-封闭原则。但是不同的是,工厂模式是在新增一个具体的产品时,会增加对应的工厂。但抽象工厂模式只有在新增一个类型的具体产品时才需要新增工厂。也就是说,工厂模式的一个工厂只能创建一个产品,而抽象工厂模式的一个工厂是创建一类产品。
场景:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而是客户端不依赖于具体实现。
实现方式:
抽象工厂模式包含如下角色:
- 抽象工厂(AbstractFactory):用于声明生成抽象产品的方法。
- 具体工厂(ConcreteFactory):实现抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- 抽象产品(AbstractProduct):为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法。
- 具体产品(Product):定义具体工厂生成的具体类型对象,实现抽象产品接口中定义的业务方法。
举例
假如我们是一家汽车代工厂,我们负责奔驰和特斯拉两家公司制造车子。我们可以认为奔驰是加油的车子,特斯拉是充电的车子。其中奔驰和特斯拉都有跑车和商务车两种类型。
以上场景,我们就可以把跑车和商务车分别对峙,对于跑车有单独的工厂创建,商务车也有单独的工厂。这样,以后无论再帮哪家厂商造车,只要是跑车或者商务车我们就不需要再引入工厂。同样,如果要增加一种类型的车,比如越野车,我们也不需要对跑车或者商务车做任何东西的修改。
(1)抽象产品: 奔驰车和特斯拉
/**
* 奔驰接口 - 抽象产品
*/
public interface BenzCar {
/**
* 加油车
*/
public void gasUp();
}
/**
* 特斯拉 - 抽象产品
*/
public interface TeslaCar {
/**
* 充电
*/
public void charge();
}
(2)具体产品:奔驰商务车、奔驰跑车、特斯拉商务车、特斯拉跑车
/**
* 奔驰商务车 - 具体产品
*/
public class BenzBusinessCar implements BenzCar {
@Override
public void gasUp() {
System.out.println("奔驰商务车加油");
}
}
/**
* 奔驰跑车 - 具体产品
*/
public class BenzSportCar implements BenzCar {
@Override
public void gasUp() {
System.out.println("给奔驰跑车加油");
}
}
/**
* 特斯拉商务车 - 具体产品
*/
public class TeslaBusinessCar implements TeslaCar {
@Override
public void charge() {
System.out.println("特斯拉商务车加电");
}
}
/**
* 特斯拉电动车 - 具体产品
*/
public class TeslaSportCar implements TeslaCar {
@Override
public void charge() {
System.out.println("特斯拉跑车充电");
}
}
(3)抽象工厂:汽车工厂
/**
* 汽车 - 抽象工厂
*/
public interface CarFactory {
public BenzCar getBenzCar();
public TeslaCar getTeslaCar();
}
(4)具体工厂:商务车工厂、跑车工厂
/**
* 商务车工厂 - 具体工厂
* @author <a href="zhang_gengying@dahuatech.com">zhang_gengying</a>
* @Date: 2022/2/21
* @Since 1.1.1
*/
public class BusinessCarFactory implements CarFactory {
@Override
public BenzCar getBenzCar() {
return new BenzBusinessCar();
}
@Override
public TeslaCar getTeslaCar() {
return new TeslaBusinessCar();
}
}
/**
* 跑车工厂 - 具体工厂1
*/
public class SportCarFactory implements CarFactory {
@Override
public BenzCar getBenzCar() {
return new BenzSportCar();
}
@Override
public TeslaCar getTeslaCar() {
return new TeslaSportCar();
}
}
开闭原则的倾斜性
"开闭原则" 要求系统对扩展开放,对修改关闭,通过扩展达到增强的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
增加产品族:对于增加新的产品族,工厂方法模式很好的支持了"开闭原则",对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持"开闭原则"。
抽象工厂模式的这种性质称为"开闭原则"的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。
抽象工厂模式、工厂方法模式、简单工厂之间的关系
当抽象工厂模式中每一个具体工厂类只能创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式。
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
当抽象工厂模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品,并将创建对象的工厂方法设计为静态方法时,抽象工厂模式就退化成简单工厂模式。