这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战
带你了解不一样的工厂模式
工厂模式(Factory Pattern)是我们最常见也是最常用的设计模式之一,工厂模式按照类的流程上来讲是属于创建型模式,它提供了一种创建对象的最佳方式。
工厂模式的历史由来
在现实生活中,社会在进步,我们都是从原始社会、农耕社会、工业革命、现代工厂等发展过来,
原始社会就像是自给自足,自己种植自己的东西相当于没有工厂。农耕社会就相当于自己村庄开了一家酒坊,只能简单的生产固定的几种酒,这种就相当于简单工厂,只有少量或者几种东西可以生产。工业革命时代就相当于自己开了一家工厂,可以自己生产产品也可以向外面销售这些产品,比起农耕时代,可以生产不同的产品,相当于是一个普通的工厂方法。 现代工厂就开一个多条流水线工程,给你一个车辆设计,然后内部车辆的零件如何实现,车辆是如何拼接,用户都不需要管,只需要知道怎么使用这个车辆就行。现代产业链代工厂就相当于抽象工厂
简单工厂模式(Simple Factory Pattern )
简单工厂模式(Simple Factory Pattern )是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于GOF 23种设计模式。简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
通过一下代码来展示简单工厂
- AbstractCar
public abstract class AbstractCar {
String engine;
public abstract void run();
}
定义抽象类,实现公共的方法和变量 如果定义了抽象类和接口,就会有多实现,多实现就代表着会有多个功能的扩展
- Factory
public class Factory {
public AbstractCar newCar(String type) {
/**
* 简单工厂一切从简
*/
if ("van".equals(type)) {
return new VanCar();
} else if ("min".equals(type)) {
return new MinCar();
}
return null;
}
}
定义一个基本的工厂实现,里面实现了只有min和van的两个车型的具体实现,对于其他车型的具体实现都没有,表示该工厂只能生产min和van两种车型。
- MinCar
public class MinCar extends AbstractCar {
public MinCar() {
this.engine = "轿车柴油机";
}
@Override
public void run() {
System.out.println(engine + ":轿车");
}
}
定义min车型类,min车型继承抽象Cat类,并声明构造方法和重写run方法。
- VanCar
public class VanCar extends AbstractCar {
public VanCar() {
this.engine = "货车柴油机";
}
@Override
public void run() {
System.out.println(engine + ":货车");
}
}
定义van车型类,van车型继承抽象Cat类,并声明构造方法和重写run方法。
- 流程图
通过上述代码,子类VanCar和MinCar都继承父类AbstractCar,同时子类都初始化属于自己的构造方法并重写父类的run方法,Factory工厂类里面有只有子类的VanCar和MinCar的创建方法,其他的Car的都没有引用的方法。
如果业务扩展,我继续増加Car的方法甚至更多,那么我们工厂类的依赖会变得越来越臃肿中。因此,我们要想办法把这种依赖减弱,把创建细节隐藏。虽然目前的代码中,我们创建对象的过程并不复杂,但从代码设计角度来讲不易于扩展。
简单工厂主要有三个角色分类
- Factory:工厂角色
- Product:抽象产品角色
- ConcreteProduct:具体产品角色,VanCar、MiniCar
简单工厂的缺点违背开闭,扩展不易
简单工厂使用场景工厂类适合创建比较少的类
简单工厂的优点只需要创建一个正确的参数,就可以获得所需要的对象,不需要考虑创建的细节
工厂方法模式(Factory Method Pattern)
工厂方法模式(Fatory Method Pattern )是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。
工厂方法模式主要解决产品扩展的问题,在简单工厂中,随看产品链的丰富,如果每个课程的创建逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,并不便于维护。根据单一职责原则我们将职能继续拆分,专人干专事。
通过一下代码来展示工厂方法
- AbstractCar
public abstract class AbstractCar {
public String engine;
public abstract void run();
}
定义抽象类,实现车辆创建的公共的方法和变量
- AbstractCarFactory
public interface AbstractCarFactory {
public AbstractCar newCar();
}
定义车辆工程的接口,并定义创建新车辆的方法newCar()
- MinCar
public class MinCar extends AbstractCar {
public MinCar(){
this.engine="轿车发动机";
}
@Override
public void run() {
System.out.println("轿车");
}
}
定义min车型类,min车型继承抽象Cat类,并声明构造方法和重写run方法。
- MinCarFactory
public class MinCarFactory implements AbstractCarFactory {
@Override
public AbstractCar newCar() {
return new MinCar();
}
}
定义MinCar工厂方法,并实现了car的接口工厂,可以重写新建车辆的方法,可以定制化生产MinCar车辆的。
- VanCar
public class VanCar extends AbstractCar {
public VanCar() {
this.engine = "货车柴油机";
}
@Override
public void run() {
System.out.println(engine + ":货车");
}
}
定义VanCar车型类,Van车型继承抽象Cat类,并声明构造方法和重写run方法。
- VanCarFactory
public class VanCarFactory implements AbstractCarFactory {
@Override
public AbstractCar newCar() {
return new VanCar();
}
}
定义VanCar工厂方法,并实现了car的接口工厂,可以重写新建车辆的方法,可以定制化生产MinCar车辆的。
- 流程图
通过上述代码可知,工厂模式是把创建方法封装成一个接口,有新增的类去实现接口,然后重写该接口,从而达到自由添加子类的实现
-
工厂方法适用于场景
- 1、创建对象需要大量重复的代码。
- 2、客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
- 3、一个类通过其子类来指定创建哪个对象。
-
工厂方法的缺点
- 1、类的个数容易过多,増加复杂度。
- 2、増加了系统的抽象性和理解难度。
-
工厂方法的角色
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式(Abastract Factory Pattern )是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。
应用层不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
通过一下代码来展示工厂方法
- AbstractCar
public abstract class AbstractCar {
public String engine;
public abstract void run();
}
定义抽象车辆方法,定义变量和run方法
- AbstractFactory
public interface AbstractFactory {
public AbstractCar newCar();
public AbstractMask newMask();
}
定义一个抽象的工厂,可以定义生产车辆和生产口罩的方法
- AbstractCarFactory
public abstract class AbstractCarFactory implements AbstractFactory {
@Override
public AbstractCar newCar() {
return null;
}
@Override
public abstract AbstractMask newMask();
}
定义车辆的抽象工厂,并实现公共抽象工厂,里面可以重写新建车辆的方法
- AbstractMask
public abstract class AbstractMask {
public Integer price;
public abstract void protectedMy();
}
定义抽象口罩类,并声明口罩的价格变量和类型方法
- AbstractMaskFactory
public abstract class AbstractMaskFactory implements AbstractFactory {
@Override
public AbstractMask newMask() {
return null;
}
@Override
public abstract AbstractCar newCar();
}
定义口罩的抽象工厂,并实现公共抽象工厂,里面可以重写新建口罩的方法
- CommonMask
public class CommonMask extends AbstractMask{
public CommonMask(){
this.price = 1;
}
@Override
public void protectedMy() {
System.out.println("普通口罩");
}
}
定义一个实体口罩类,继承抽象口罩类,并自定义重写符合自己的口罩类型
- CommonMaskFactory
public class CommonMaskFactory extends AbstractMaskFactory {
@Override
public AbstractMask newMask() {
return new CommonMask();
}
@Override
public AbstractCar newCar() {
return null;
}
}
定义cmmon口罩类生产工厂,可以只生产common一种口罩的方法
- MinCar
public class MinCar extends AbstractCar {
public MinCar(){
this.engine="轿车发动机";
}
@Override
public void run() {
System.out.println("轿车");
}
}
定义一个实体车辆类,继承抽象车辆类,并自定义重写符合自己的车辆类型
- MinCarFactory
public class MinCarFactory extends AbstractCarFactory {
@Override
public MinCar newCar() {
return new MinCar();
}
@Override
public AbstractMask newMask() {
return null;
}
}
定义min车辆类生产工厂,可以只生产min一种车辆类型的的方法
- 流程图
上面的代码完整地描述了两个产品族口罩和车辆。抽象工厂非常完美清晰地描述这样一层复杂的关系。
但是,当我们再继续扩展其他产品等级,比如将充电的行为添加到接口中,那么我们的代码从抽象工厂,到具体工厂要全部调整,很显然不符合开闭原则。
-
抽象工厂的缺点
- 1、规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
- 2、増加了系统的抽象性和理解难度。
-
抽象工厂的使用场景
- NumberFormat、SimpleDateFormat
- LoggerFactory
- SqlSessionFactory:MyBatis
- BeanFactory:Spring的BeanFactory
工厂模式的退化
当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;
当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。