重温设计模式之 Factory

Posted 阿里技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重温设计模式之 Factory相关的知识,希望对你有一定的参考价值。


前言

创建型模式的核心干将,工厂、简单工厂、抽象工厂,还记得清么,一文回顾和对比下。

一  为什么需要工厂

系统中总是需要创建对象的,一般使用new()来创建对象。创建对象可以是简单的new(),也可以有复杂的加工逻辑,如果在主程序中创建对象,那么就是将主干逻辑和创建对象的非主干逻辑耦合在了一起,工厂模式要做的就是将非核心的对象创建逻辑与主干逻辑解耦,通过调用工厂的创建方法直接获取到一个对象。

二  工厂模式中的角色划分

  • 抽象产品角色(都有)

  • 具体产品角色(都有)

  • 抽象工厂角色(工厂方法模式和抽象工厂模式有)

  • 具体工厂角色(都有)

  • 上下文角色(都有)——调用工厂获取对象


三  对工厂的基本认知

工厂方法总是基于一定的入参,返回对应的产品对象,即工厂是用来生产产品的。

工厂方法可能根据不同条件创建不同的具体产品实体,因此工厂方法的返回类型是抽象产品类型。

四  工厂模式的简单划分

1  简单工厂模式

产品有抽象层,但是工厂没有抽象层,在一个工厂中根据传参创建相应的产品类型。

如果需要新增产品族(例如在A_cpu,B_cpu之外新增C_cpu),那么需要在工厂方法中进行逻辑修改,没有做到开闭原则——对扩展开放,对修改封闭。

简单工厂模式就是静态工厂模式,不属于GOF23中的模式,就是一个简单的封装,在静态工厂模式中,工厂方法是静态的,所以叫做静态工厂方法。

2  工厂方法模式

产品有抽象层,工厂也有抽象层,一个工厂对应一个产品(即一个工厂只能创建一个产品类别)。

如果新增产品,只需要新增工厂,不需要对原有工厂逻辑进行修改,符合开闭原则。

3  抽象工厂模式

产品有抽象层,工厂有抽象层,一个工厂对应多个产品(即一个工厂可以创建多个产品类别)。

用于解决有多有产品类别(芯片、主板、显卡)情况下,产品族(A产品族、B产品族)的切换替代问题。

五  简单工厂模式详解

简单工厂模式下,只有一个工厂类,工厂角色没有抽象层次。

使用这一个工厂生产出不同的产品实现,例如使用CpuFactory这一个产品类中会生产出ACpu、BCpu等具体的产品实现。

如果要新增产品实现,例如CCpu,需要修改该工厂方法的代码。

简单工厂模式中,决定生成哪个产品的逻辑在工厂内实现。


重温设计模式之 Factory


1  DEMO:抽象产品接口

package com.taobao.migao.pattern.factory.simplefactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品抽象接口:CPU */public interface Cpu { void calculate();}

2  DEMO:具体产品实现

package com.taobao.migao.pattern.factory.simplefactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品的具体实现-A的CPU */public class ACpu implements Cpu { @Override public void calculate() { System.out.println("this is A cpu"); }}

3  DEMO:具体产品实现

package com.taobao.migao.pattern.factory.simplefactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品的具体类型-B的CPU */public class BCpu implements Cpu { @Override public void calculate() { System.out.println("this is B cpu"); }}

4  DEMO:简单工厂类

package com.taobao.migao.pattern.factory.simplefactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 简单工厂类:CPU的工厂 */public class CpuFactory { /** * 返回值是产品的抽象类型 * 简单工厂模式:创建哪种具体产品类型代码在工厂内部,如果需要新增具体产品,需要修改工厂类方法 * 例如需要增加C的cpu,需要修改下面的工厂方法,不符合开-闭原则 * @return */ public static Cpu createCpu(Class classType) { if (classType.getName().equals(ACpu.class.getName())) { return new ACpu(); } else if (classType.getName().equals(BCpu.class.getName())) { return new BCpu(); } return null; }}

5  DEMO:测试类——调用工厂创建对象的客户端代码

package com.taobao.migao.pattern.factory.simplefactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 简单工厂测试类,对应程序中需要创建对象并调用对象方法的客户端代码 */public class SimpleFactoryTest { public static void main(String[] args) { Cpu cpu = CpuFactory.createCpu(BCpu.class); cpu.calculate(); }}

六  工厂方法模式详解

工厂方法模式中,对工厂也进行了抽象,一个抽象工厂还是对应一个产品类别,例如CpuFacroy接口对应生产Cpu产品,但是具体生产的时候,将具体的产品实现交给每个具体的工厂实现去生产;即在CpuFactory接口下,有ACpuFactory和BCpuFactory,分别来生产ACpu和BCpu这2中具体的产品。

工厂方法模式中具体的工厂负责创建具体的产品,工厂内部的逻辑只负责创建对应对象,决定生成什么产品的逻辑在外部客户端,客户端通过选择使用具体工厂,间接决定了生成什么产品。



1  DEMO:产品抽象接口

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品抽象接口:CPU */public interface Cpu { void calculate();}

2  DEMO:具体产品实现

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品的具体实现-A的CPU */public class ACpu implements Cpu { @Override public void calculate() { System.out.println("this is A cpu"); }}

3  DEMO:具体产品实现

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品的具体类型-B的CPU */public class BCpu implements Cpu { @Override public void calculate() { System.out.println("this is B cpu"); }}

4  DEMO:抽象工厂

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description CPU这个产品类型的抽象工厂 */public interface CpuFactory { /** * 这是CPU产品的工厂,所以专门生产CPU,返回的类型是对应产品的抽象类型 */ Cpu createCpu();}

5  DEMO:具体工厂实现

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 工厂方法模式下,一个工厂对应一个产品:一个抽象工厂对应抽象产品,一个具体工厂对应一个具体产品 */public class ACpuFactory implements CpuFactory{
@Override public Cpu createCpu() { return new ACpu(); }}

6  DEMO:具体工厂实现

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 工厂方法模式下,一个工厂对应一个产品:一个抽象工厂对应抽象产品,一个具体工厂对应一个具体产品 */public class BCpuFactory implements CpuFactory { @Override public Cpu createCpu() { return new BCpu(); }}

7  DEMO:测试类——上下文

package com.taobao.migao.pattern.factory.factorymethod;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 测试类 使用具体的工厂实现来创建产品对象 */public class FactoryMethodTest { public static void main(String[] args) { CpuFactory factory = new ACpuFactory(); Cpu cpu = factory.createCpu(); cpu.calculate(); }}

七  THINK:简单工厂&工厂方法模式的区别

简单工厂模式中工厂类没有抽象层,而工厂方法模式中工厂类有抽象工厂。

决定生成具体什么产品的逻辑在哪里实现?

  • 简单工厂模式中,客户端决定传递什么类型的参数,在工厂中根据不同的参数决定创建不同的对象,即工厂内部有决策创建产品的逻辑。


  • 工厂方法模式中,具体工厂内部很纯净,什么类型的工厂就负责创建对应的产品,决策的逻辑全部在客户端中实现。


当需要新增产品实现时,简单工厂模式需要修改工厂逻辑,工厂方法模式只需要新增具体工厂实现,不需要修改工厂内部逻辑。

八  THINK:工厂方法 & 抽象工厂模式的区别

1  工厂方法模式

工厂方法模式用于解决一个产品(Cpu),有多个产品族(ACpu,BCpu)的情况,以抽象产品作为工厂,例如CpuFactory,每个产品族对应一个具体工厂,例如ACpuFactory,BCpuFactory,即工厂方法模式以产品维度来建厂。

工厂方式模式中,多一个新的抽象产品的话需要新建立一个抽象工厂,例如新建MainboardFactory等。即如果需要新增产品线(XianKa),则需要新增抽象工厂(XianKaFactory);如果需要在某个产品(Cpu)下新增具体产品,则需要新增具体工厂(CCpuFactory)。

工厂方法模式中以抽象产品维度建厂,每个抽象产品一个工厂,当产品族(A,B,C……)增加的时候,需要为每个产品的抽象工厂新增具体工厂(CCpuFactory,CMainboardFactory,CXianKaFactory)。

2  抽象工厂模式

在工厂方法模式下,当产品线(品类:cpu/主板/显卡)和产品族(A/B/C)水平扩展后,如果要新增产品族,那么需要在所有工厂下面新增新产品族的所有产品,即在cpu工厂、主板工厂、显卡工厂……都新增C的具体工厂,这样显然改动太大,此时就要考虑使用抽象工厂模式。

抽象工厂模式下,以产品族维度来建厂,一个厂里有多个创建方法,每个创建方法负责创建一个产品线,例如有A工厂、B工厂,每个工厂里面有创建cpu的方法、创建主板的方法、创建显卡的方法,当需要新增一个产品族的时候,只需要新增一个工厂,例如C工厂,在该工厂中创建各个产品即可。

3  总结

工厂方法模式和抽象工厂模式的最大区别是工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。

九  抽象工厂模式详解

1  抽象工厂模式角色

  • 抽象产品


  • 具体产品


  • 抽象工厂:以产品族维度建工厂类,类中含有多个抽象方法,每个方法对应创建一个产品。


  • 具体工厂:具体工厂实现抽象工厂,并实现里面的所有产品创建方法,创建属于当前具体产品对象。


  • 环境类:持有抽象工厂,并可以在运行时注入具体工厂。



2  DEMO:抽象产品

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品抽象接口:CPU */public interface Cpu { void calculate();}

package com.taobao.migao.pattern.factory.abstractfactory;
/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 抽象产品:主板 */public interface Mainboard { void installCpu();}

3  DEMO:具体产品

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品的具体实现-A的CPU */public class ACpu implements Cpu { @Override public void calculate() { System.out.println("this is A cpu"); }}

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 产品的具体实现-B的CPU */public class BCpu implements Cpu { @Override public void calculate() { System.out.println("this is B cpu"); }}

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description */public class AMainboard implements Mainboard { @Override public void installCpu() { System.out.println("this is A mainboard"); }}

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description */public class BMainboard implements Mainboard { @Override public void installCpu() { System.out.println("this is B mainboard"); }}

4  DEMO:抽象工厂

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 抽象工厂,定义了工厂需要负责创建的产品 */public interface AbatractFactory { //创建CPU产品 Cpu createCpu();
//创建主板产品 Mainboard createMainboard();}

5  DEMO:具体工厂

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 具体的工厂,以产品族维度建立具体的工厂 */public class AFactory implements AbatractFactory {
@Override public Cpu createCpu() {        return new ACpu(); }
@Override public Mainboard createMainboard() {        return new AMainboard(); }}

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 具体工厂,以产品族维度建立具体的工厂 */public class BFactory implements AbatractFactory { @Override public Cpu createCpu() { return new BCpu(); }
@Override public Mainboard createMainboard() { return new BMainboard(); }}

6  DEMO:测试类——类似程序上下文

package com.taobao.migao.pattern.factory.abstractfactory;/** * @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a> * @version 1.0 * @description 抽象工厂测试类,持有具体的工厂实例,调用工厂的方法获取具体的产品对象 */public class AbstractFactoryTest { public static void main(String[] args) {        //注入A工厂 AbatractFactory factory = new AFactory();
Cpu cpu = factory.createCpu(); Mainboard mainboard = factory.createMainboard();
cpu.calculate(); mainboard.installCpu(); }}

十  THINK:工厂模式中的方法一定是静态的吗?

在简单工厂中,工厂方法没有对应的抽象,可以定义为静态的。

在工厂方法模式和抽象工厂模式中,工厂都有对应的抽象接口,而接口中的抽象方法不能定义为静态,所以工厂方法也不能是静态的。

十一  THINK:对于接口中static的理解

接口interface以及接口中的方法都是public abstract的。

接口中的方法都是抽象方法,没有方法体,因此也不允许使用static来修饰(static方法表示可以被类调用,接口因为没有功能体,所以没有人调用,所以不允许声明为static)。

但是从JDK8开始,接口中方法可以有static,此时的方法必须有方法体,即接口中可以含有非抽象的方法,和抽象类一样了,接口中非抽象的方法不需要被实现,抽象的方法必须要求子类实现。

十二  工厂模式 & 抽象工厂的使用场景

一个系统不应当依赖于产品类实例如何被创建、组合、表达的细节,这是所有工厂模式都要关注解决的问题。

当系统中的产品有多个产品族,虽然对于任何一个具体请求只属于其中一个产品族,但是对于系统而言,应当面向产品族设计,即使用抽象工厂模式。

当系统中有多个产品族,并且这个产品族中的产品通常是在一起使用,一起创建的,如果这种约束需要在系统设计中体现出来,那么应当使用抽象工厂模式(例如:不管是A产品族,还是B产品族中的芯片、主板、磁盘这些产品通常需要一起创建)。

十三  抽象工厂模式的优缺点

1  抽象工厂的优点

分离了接口和实现

客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口,也就是说客户端从具体的产品中实现了解耦。

使切换产品族变得容易

因为一个具体的工厂代表的是一个产品族,比如上面例子中的A系列到B系列只需要切换一下具体的工厂。

2  抽象工厂的缺点

不太容易扩展新的产品

如果需要给这个产品族添加一个新的产品,那么就需要修改抽象工厂,需要在抽象工厂中添加新产品创建方法,同时需要给所有的具体工厂增加接口。

十四  最佳实践

都使用抽象工厂模式,按照产品族维度来建立工厂,如果只有一个产品那么工厂中就一个方法,如果有多个产品就多个方法。



技术公开课
建立 Serverless 思维

本课程从 Serverless 基本概念、为开发者带来的实际价值、常见的架构模式以及技术选型四个方面,带大家学习了解 Serverless。


点击“阅读原文”开始学习吧~

以上是关于重温设计模式之 Factory的主要内容,如果未能解决你的问题,请参考以下文章

2021-07月报

重温Spring之AOP

Head First 设计模式之工厂模式(Factory Pattern)

Java设计模式之工厂模式(Factory Pattern)

Java设计模式之工厂模式(Factory Pattern)

C#设计模式之二工厂方法模式(Factory Method Pattern)创建型