工厂模式白话 - 3种都有哦
前言
工厂模式(Factory Pattern)里所谓的“工厂”和现实生活中的工厂一样
主要作用都是生产产品
像食品厂、服装厂、汽车厂生产吃的、穿的、开的
设计模式里的工厂则是生产对象
划分
工厂模式可分为简单工厂、工厂方法、抽象工厂3种
有啥不同呢?
以汽车品牌举例,有别克、凯迪拉克、比亚里、特斯拉等等
1 简单工厂模式
好比一个能生产任何品牌的轿车工厂(一个轿车工厂,能生产别克、凯迪拉克、比亚迪、特斯拉,简直不要太强大)
关键实现 ①工厂类提供工厂方法;②工厂方法接收参数;③通过参数实例化不同的产品
1.1 代码实现
既然是一个 method + param 就能实例化出不同的对象
那就需要用到 OOP 的多态
先定义一个轿车对象的ICar
接口(造出来的轿车能启动、能跑)
// 轿车
public interface ICar {
void start();
void run();
}
复制代码
实现ICar
接口(别克轿车、凯迪拉克轿车)
public class BuickCar implements ICar {
@Override
public void start() {
System.out.println("别克轿车启动");
}
@Override
public void run() {
System.out.println("别克轿车定速巡航");
}
}
public class CadillacCar implements ICar {
// 很简单,不写了
}
复制代码
然后声明一个轿车工厂(工厂类)并定义造车方法(工厂方法)
public class CarFactory {
public ICar buildCar(String carName) {
ICar car = null;
if ("别克".equals(carName)) {
car = new BuickCar();
} else if ("凯迪拉克".equals(carName)) {
car = new CadillacCar();
}
return car;
}
}
复制代码
OK。分别造一辆别克、一辆凯迪拉克的轿车
public class SimpleFactoryDemo {
public static void main(String[] args) {
// 造一辆别克轿车
CarFactory carFactory = new CarFactory();
ICar buickCar = carFactory.buildCar("别克");
buickCar.start();
buickCar.run();
// 造一辆凯迪拉克轿车
ICar cadillacCar = carFactory.buildCar("凯迪拉克");
cadillacCar.start();
cadillacCar.run();
}
}
复制代码
1.2 优缺点
它的优点就是够简单
至于缺点
比如这个简单工厂太牛了,还能造奔驰、宝马、奥迪等等100多个品牌的轿车
那么使用简单工厂模式会有2个问题:
- 工厂类中代码过多:CarFactory 里
buildCar()
需要加上100多个 if...else,看着就头疼 - 违反开闭原则:改
buildCar()
时要是手抖误触,凯迪拉克
变成凯迪克
,那原来的凯迪拉克就造不出来了
可见,简单工厂模式不适用于有很多子产品的场景
2 工厂方法模式
好比简单工厂的专精版本,改用多个工厂、每个工厂生产自己品牌的轿车(别克工厂、凯迪拉克工厂、比亚迪工厂等等专门造轿车)
关键实现 ①抽象出一个工厂类;②工厂类提供工厂方法;③具体的工厂(子产品工厂)实现工厂类
2.1 代码实现
首先抽象出一个工厂类
为啥叫抽象呢?是因为这个工厂不干具体的事,只定义了一个造车方法
// 抽象工厂--负责生产ICar
public abstract class CarFactory {
// 工厂方法
public abstract ICar buildCar();
}
复制代码
实现具体的工厂(别克工厂、凯迪拉克工厂)
public class BuickFactory extends CarFactory {
@Override
public ICar buildCar() {
return new BuickCar();
}
}
public class CadillacFactory extends CarFactory {
@Override
public ICar buildCar() {
return new CadillacCar();
}
}
复制代码
OK。分别造一辆别克、一辆凯迪拉克的轿车
public class FactoryMethodDemo {
public static void main(String[] args) {
// 别克轿车
CarFactory buickFactory = new BuickFactory();
ICar buickCar = buickFactory.buildCar();
buickCar.start();
buickCar.run();
// 凯迪拉克轿车
CarFactory cadillacFactory = new CadillacFactory();
ICar cadillacCar = cadillacFactory.buildCar();
cadillacCar.start();
cadillacCar.run();
}
}
复制代码
2.2 工厂方法 vs 简单工厂
工厂方法模式中每一个子产品都对应一个工厂,解决了子产品过多时,简单工厂模式工厂类过于庞大的问题
符合开闭原则,增加车辆品牌只需增加具体类和对应的工厂类就OK(当然这也是它的缺点,系统类中的个数会成倍增加)
3 抽象工厂模式
像是专业工厂的做大版本,不满足于只生产轿车了,还要造SUV。改为多个工厂、每个工厂生产自己品牌的轿车、SUV(别克工厂、凯迪拉克工厂、比亚迪工厂等等,但不只造轿车了,还造SUV)
关键实现 ①抽象出一个工厂类;②工厂类提供工厂方法;③具体的工厂(子产品工厂)实现工厂类
3.1 产品等级 & 产品族
What?这关键实现不和工厂方法模式一毛一样吗?
确实
不过抽象工厂可以生产轿车和SUV,而工厂方法模式只能生产轿车,这就是它们的区别
用抽象工厂模式的概念来说,这里所谓的轿车和SUV叫产品族,而别克、凯迪拉克、比亚迪等叫产品等级
3.2 代码实现
新增一个SUV对象的ISuv
接口(造出来的SUV能启动、能跑)
public interface ISuv {
void start();
void run();
}
复制代码
实现ISuv
接口(别克SUV、凯迪拉克SUV)
public class BuickSuv implements ISuv {
@Override
public void start() {
System.out.println("别克SUV启动");
}
@Override
public void run() {
System.out.println("别克SUV定速巡航");
}
}
public class CadillacSuv implements ISuv {
// 很简单,不写了
}
复制代码
抽象出一个工厂类
但这个工厂类定义了两个造车方法(2个产品等级)
// 抽象工厂
public abstract class AbstractFactory {
// 造轿车
public abstract ICar buildCar();
// 造SUV
public abstract ISuv buildSuv();
}
复制代码
实现具体的工厂(别克工厂、凯迪拉克工厂)
public class BuickFactory extends AbstractFactory {
@Override
public ICar buildCar() {
return new BuickCar();
}
@Override
public ISuv buildSuv() {
return new BuickSuv();
}
}
public class CadillacFactory extends AbstractFactory {
@Override
public ICar buildCar() {
return new CadillacCar();
}
@Override
public ISuv buildSuv() {
return new CadillacSuv();
}
}
复制代码
OK。分别造一辆别克轿车、一辆凯迪拉克SUV
public class AbstractFactoryDemo {
public static void main(String[] args) {
AbstractFactory buickFactory = new BuickFactory();
// 别克轿车
ICar buickCar = buickFactory.buildCar();
buickCar.start();
buickCar.run();
// 凯迪拉克SUV
AbstractFactory cadillacFactory = new CadillacFactory();
ISuv cadillacSuv = cadillacFactory.buildSuv();
cadillacSuv.start();
cadillacSuv.run();
}
}
复制代码
3.3 优缺点
优点 包含工厂方法的优点,且通过实例工厂类对产品族进行约束
想象一下成套成套的换QQ皮肤,可以用A皮肤的工厂拿到A套装,用B皮肤的工厂拿到B套装,而不会出现拿乱套装的情况
缺点 拓展产品族困难(扩展产品等级倒是很容易,新增工厂就行)
拓展产品族要在
AbstractFactory
中增加抽象方法,导致所有实现了AbstractFactory
的类都要修改,工作量太大
总结
简单工厂 用一个工厂类生产同一产品等级的对象(一个轿车工厂,能生产别克、凯迪拉克、比亚迪、特斯拉等),足够简单,但不符合开闭原则,子产品过多时工厂类会很庞大
工厂方法 简单工厂的专精版本,多个工厂类生产同一产品等级的对象(有多个工厂、每个工厂生产自己品牌的轿车),符合开闭原则,解决了简单工厂子产品过多时工厂类会很庞大的缺点,但系统类中的个数也会成倍增加
抽象工厂 专业工厂的做大版本,多个工厂类生产一个产品族的对象(每个工厂不满足于只生产轿车了还要造SUV),包含工厂方法的优点,且通过实例工厂类对产品族进行约束;拓展产品族困难,拓展产品等级简单
工厂方法加一个产品等级就变成了抽象工厂,抽象工厂只有一个产品等级时就变成了工厂方法,实际开发时不用纠结到底用哪个模式。此外,强大的 Spring 通过 Bean 注入和反射机制规避了简单工厂的缺点,基于 SpringBoot 开发时可用@Autowried + Map
实现简单工厂哦