🔥 核心
一个工厂能够根据需要产生不同的产品。
如果是根据参数生产产品,则称为简单工厂模式;定义一个创建对象的工厂接口,其子类自己已经决定好了生产哪一种产品,则称为工厂模式;这个子类工厂能生产一套产品。则称为抽象工厂模式。
🙁 问题场景
你现在正在为一个电脑设备商店开发系统。
最初的需求是,工厂可以根据订单生产不同品牌的 电脑
。你三下五除二,写出了一个 电脑设备工厂
,这个工厂可以根据传入的参数生产出不同品牌的电脑,联想啊,苹果啊…
你想了想,一个工厂能生产两种品牌的电脑,似乎有些不符合实际。你灵光一闪,将刚刚的 电脑设备工厂
声明为了抽象接口,然后接着建立了两个子工厂—— 联想设备工厂
和 苹果设备工厂
,这两个工厂,分别用于生产 联想电脑
和 苹果电脑
。
这时,这所电脑设备商店越做越大,不仅卖电脑,也开始卖 鼠标
和 键盘
。而且,来买电脑设备的人,都倾向于买一套相同品牌的设备,也就是“全家桶”,而不会混搭着买。
怎么办呢?没有人想一边看着联想的电脑、一边用着苹果的鼠标和其他不知道啥牌子的键盘,可怎样才能一次生产出成套的设备呢?
🙂 解决方案
怎么生产出全家桶?
很简单啊!你已经有了 联想设备工厂
和 苹果设备工厂
,让俩工厂不仅仅生产 电脑
,同时也生产 鼠标
和 键盘
不久行了吗?也就是说,让每个不同品牌的工厂,生产自己成套的产品。
联想设备工厂:联想电脑、联想鼠标、联想键盘…
苹果设备工厂:苹果电脑、苹果鼠标、苹果键盘…
嗯嗯,赏心悦目的设计。
🌈 有趣的例子
圆形(Circle)
、正方形(Square)
、三角形(Triangle)
接口均继承自 图形(Shape)
接口,它们又被实现为9种带颜色的具体图形:[红色|蓝色|绿色]的[圆形|正方形|三角形]
。
红色图形工厂(RedFactory
)、蓝色图形工厂(BlueFactory
)、绿色图形工厂(GreenFactory
) 都可以产生各自颜色的一套图形。
三种图形的接口
interface Shape {
void draw();
}
圆形
interface Circle extends Shape { }
正方形
interface Square extends Shape { }
三角形
interface Triangle extends Shape { }
[红色|蓝色|绿色][圆形|正方形|三角形]
class RedCircle implements Circle { @Override public void draw() { System.out.println("我是红色的圆形 >_<"); }}
class BlueCircle implements Circle { @Override public void draw() { System.out.println("我是蓝色的圆形 >_<"); }}
class GreenCircle implements Circle { @Override public void draw() { System.out.println("我是绿色的圆形 >_<"); }}
class RedSquare implements Square { @Override public void draw() { System.out.println("我是红色的正方形 >_<"); }}
class BlueSquare implements Square { @Override public void draw() { System.out.println("我是蓝色的正方形 >_<"); }}
class GreenSquare implements Square { @Override public void draw() { System.out.println("我是绿色的正方形 >_<"); }}
class RedTriangle implements Triangle { @Override public void draw() { System.out.println("我是红色的三角形 >_<"); }}
class BlueTriangle implements Triangle { @Override public void draw() { System.out.println("我是蓝色的三角形 >_<"); }}
class GreenTriangle implements Triangle { @Override public void draw() { System.out.println("我是绿色的三角形 >_<"); }}
抽象工厂接口
interface AbstractFactory {
Shape getCircle();
Shape getSquare();
Shape getTriangle();
}
红色图形工厂
class RedFactory implements AbstractFactory {
@Override
public Shape getCircle() {
return new RedCircle();
}
@Override
public Shape getSquare() {
return new RedSquare();
}
@Override
public Shape getTriangle() {
return new RedTriangle();
}
}
蓝色图形工厂
class BlueFactory implements AbstractFactory {
@Override
public Shape getCircle() {
return new BlueCircle();
}
@Override
public Shape getSquare() {
return new BlueSquare();
}
@Override
public Shape getTriangle() {
return new BlueTriangle();
}
}
绿色图形工厂
class GreenFactory implements AbstractFactory {
@Override
public Shape getCircle() {
return new GreenCircle();
}
@Override
public Shape getSquare() {
return new GreenSquare();
}
@Override
public Shape getTriangle() {
return new GreenTriangle();
}
}
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
// 创建一个红色图形工厂
AbstractFactory redFactory = new RedFactory();
// 生产的图形是成套的红色
redFactory.getCircle().draw();
redFactory.getSquare().draw();
redFactory.getTriangle().draw();
// 创建一个蓝色图形工厂
AbstractFactory blueFactory = new BlueFactory();
// 生产的图形是成套的蓝色
blueFactory.getCircle().draw();
blueFactory.getSquare().draw();
blueFactory.getTriangle().draw();
// 创建一个绿色图形工厂
AbstractFactory greenFactory = new GreenFactory();
// 生产的图形是成套的绿色
greenFactory.getCircle().draw();
greenFactory.getSquare().draw();
greenFactory.getTriangle().draw();
}
}
我是红色的圆形 >_<
我是红色的正方形 >_<
我是红色的三角形 >_<
我是蓝色的圆形 >_<
我是蓝色的正方形 >_<
我是蓝色的三角形 >_<
我是绿色的圆形 >_<
我是绿色的正方形 >_<
我是绿色的三角形 >_<
☘️ 使用场景
◾️如果代码需要与多个不同系列的相关产品交互,但是由于无法提前获取相关信息,或者出于对未来扩展性的考虑,你不希望代码基于产品的具体类进行构建,在这种情况下,你可以使用抽象工厂。
抽象工厂为你提供了一个接口,可用于创建每个系列产品的对象。只要代码通过该接口创建对象,那么你就不会生成与应用程序已生成的产品类型不一致的产品。
◾️如果你有一个基于一组抽象方法的类,且其主要功能因此变得不明确,那么在这种情况下可以考虑使用抽象工厂模式。
在设计良好的程序中,每个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
🧊 实现方式
(1)以不同的产品类型与产品变体为维度绘制矩阵。
(2)为所有产品声明抽象产品接口。然后让所有具体产品类实现这些接口。
(3)声明抽象工厂接口,并且在接口中为所有抽象产品提供一组构建方法。
(4)为每种产品变体实现一个具体工厂类。
(5)在应用程序中开发初始化代码。该代码根据应用程序配置或当前环境,对特定具体工厂类进行初始化。然后将该工厂对象传递给所有需要创建产品的类。
(6)找出代码中所有对产品构造函数的直接调用,将其替换为对工厂对象中相应构建方法的调用。
🎲 优缺点
➕ 你可以确保同一工厂产生的产品相互匹配。
➕ 你可以避免客户端与具体产品代码的耦合。
➕ 单一职责原则。你可以将产品生成代码抽取到同一位置,使得代码易于维护。
➕ 开闭原则。无需更改现有客户端代码,你就可以在程序中引入新的产品类型。
➖ 由于采用该模式需要引入众多的接口和类,代码可能会变得非常复杂。
🌸 补充
至此,三种工厂模式已经讲解完毕(简单工厂模式、工厂模式、抽象工厂模式)。
你可以尝试用自己的话复述一下它们的递进关系,以更好的理解它们——它们实在是太重要了!