23种设计模式-工厂模式

工厂模式(常用)

  • ⼯⼚模式介绍:
    • 它提供了⼀种创建对象的最佳⽅式,我们在创建对象时 不会对客户端暴露创建逻辑,并且是通过使⽤⼀个共同 的接⼝来指向新创建的对象。
  • 例⼦:
    • ⼯⼚⽣产电脑,除了A品牌、还可以⽣产B、C、D品牌 电脑;
    • 业务开发中,⽀付很常⻅,⾥⾯有统⼀下单和⽀付接 ⼝,具体的⽀付实现可以微信、⽀付宝、银⾏卡等;
  • ⼯⼚模式有 3 种不同的实现⽅式:
    • 简单⼯⼚模式:通过传⼊相关的类型来返回相应的类,这 种⽅式⽐较单 ⼀,可扩展性相对较差;
    • ⼯⼚⽅法模式:通过实现类实现相应的⽅法来决定相应 的返回结果,这种⽅式的可扩展性⽐较强;
    • 抽象⼯⼚模式:基于上述两种模式的拓展,且⽀持细化 产品;
  • 应⽤场景:
    • 解耦:分离职责,把复杂对象的创建和使⽤的过程分开
    • 复⽤代码 降低维护成本:
      • 如果对象创建复杂且多处需⽤到,如果每处都进⾏编写,则很多重复代码,如果业务逻辑发⽣了改 变,需⽤四处修改;
      • 使⽤⼯⼚模式统⼀创建,则只要修改⼯⼚类即可, 降低成本;

工厂模式——简单工厂模式(使用最多)

  • 简单⼯⼚模式(静态工厂)

    • ⼜称静态⼯⼚⽅法, 可以根据参数的不同返回不同类的实例,专⻔定义⼀个类来负责创建其他类的实例,被创建的实例通常都具有共同的⽗类;
    • 由于⼯⼚⽅法是静态⽅法,可通过类名直接调⽤,⽽且只需要传⼊简单的参数即可;
  • 核⼼组成

    • Factory:⼯⼚类,简单⼯⼚模式的核⼼,它负责实现 创建所有实例的内部逻辑
    • IProduct:抽象产品类,简单⼯⼚模式所创建的所有对象的⽗类,描述所有实例所共有的公共接⼝
    • Product:具体产品类,是简单⼯⼚模式的创建⽬标
  • 实现步骤

    • 创建抽象产品类,⾥⾯有产品的抽象⽅法,由具体的产 品类去实现
    • 创建具体产品类,继承了他们的⽗类,并实现具体⽅法
    • 创建⼯⼚类,提供了⼀个静态⽅法createXXX()⽤来⽣产产品,只需要传⼊你想产品名称
  • 优点:

    • 将对象的创建和对象本身业务处理分离可以降低系统的 耦合度,使得两者修改起来都相对容易。
  • 缺点:

    • ⼯⼚类的职责相对过重,增加新的产品需要修改⼯⼚类的判断逻辑,这⼀点与开闭原则是相违背
    • 即开闭原则(Open Close Principle)对扩展开放,对 修改关闭,程序需要进⾏拓展的时候,不能去修改原有 的代码,实现⼀个热插拔的效果
    • 将会增加系统中类的个数,在⼀定程度上增加了系统的复杂度和理解难度,不利于系统的扩展和维护,创建简单对象就不⽤模式

下面我们来简单使用一下简单(静态)工厂设计模式:

功能描述:

我们简单使用伪代码模拟一下支付流程:

创建IProduct 抽象产品接口——IPay


/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: IPay抽象统一支付下单接口
 */
public interface IPay {
    
    

    /**
     * 统一下单
     */
    void unifiedOrder();
}

创建支付宝支付具体实现类–AliPay

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 支付宝支付具体实现类
 */
public class AliPay implements IPay{
    
    
    @Override
    public void unifiedOrder() {
    
    
        System.out.println("支付宝支付统一下单...");
    }
}

创建微信支付具体实现类–WeChatPay


/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 微信支付具体实现类
 */
public class WeChatPay implements IPay{
    
    
    @Override
    public void unifiedOrder() {
    
    
        System.out.println("微信支付统一下单...");
    }
}

创建一个简单支付工厂类(静态工厂类)–SimplePayFactory


/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 简单支付工厂类(静态工厂类)
 */
public class SimplePayFactory {
    
    

    /**
     * 工厂创建方法:
     * 根据参数返回对应的支付对象
     *
     * @param payType
     * @return
     */
    public static IPay createPay(String payType) {
    
    
        if (payType == null) {
    
    
            return null;
        } else if (payType.equalsIgnoreCase("WECHAT_PAY")) {
    
    
            return new WeChatPay();
        } else if (payType.equalsIgnoreCase("ALI_PAY")) {
    
    
            return new AliPay();
        }
        // 如果需要扩展,可以编写更剁
        return null;
    }
}

测试使用简单支付工厂:

package com.iswhl.EasyFactory;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 简单支付工厂类(静态工厂类)
 */
public class SimplePayFactory {
    
    

    /**
     * 工厂创建方法:
     * 根据参数返回对应的支付对象
     *
     * @param payType
     * @return
     */
    public static IPay createPay(String payType) {
    
    
        if (payType == null) {
    
    
            return null;
        } else if (payType.equalsIgnoreCase("WECHAT_PAY")) {
    
    
            return new WeChatPay();
        } else if (payType.equalsIgnoreCase("ALI_PAY")) {
    
    
            return new AliPay();
        }
        // 如果需要扩展,可以编写更剁
        return null;
    }
}

上述就是工厂设计模式——简单工程(静态工厂的一个简单使用例子),那么我们来分析下其缺点与不足之处:

需求

  • 如果我需要额外再添加一个A银行的银行卡支付,那么就需要在SimplePayFactory 类中添加响应的判断逻辑,比如再加一个if判断,添加一个A银行支付的逻辑
  • 而如果再需要一个B银行的银行卡支付,那么还需要再添加一个if判断 添加一个B银行支付的逻辑,依次加下去…
  • 那么这就违背了⼯⼚类要遵循的开闭原则(Open Close Principle)(对扩展开放,对修改关闭,程序需要进⾏拓展的时候,不能去修改原有的代码,实现⼀个热插拔的效果),这样就导致,每次扩展功能的时候都需要添加新的逻辑,并且需要对工厂类进行修改,如果是真实复杂的业务,这就增加了成本。

下面我们来看一下工厂方法模式是如何解决简单工厂模式的这一缺点

工厂模式——工厂方法模式

  • ⼯⼚⽅法模式

    • ⼜称⼯⼚模式,是对简单⼯⼚模式的进⼀步抽象化,其 好处是可以使系统在不修改原来代码的情况下引进新的 产品,即满⾜开闭原则

    • 通过⼯⼚⽗类定义负责创建产品的公共接⼝,通过⼦类 来确定所需要创建的类型

    • 相⽐简单⼯⼚⽽⾔,此种⽅法具有更多的可扩展性复⽤性,同时也增强了代码的可读性

    • 将类的实例化(具体产品的创建)延迟到⼯⼚类的⼦类 (具体⼯⼚)中完成,即由⼦类来决定应该实例化哪⼀ 个类

  • 核⼼组成

    • IProduct:抽象产品接口,描述所有实例所共有的公共接⼝
    • Product:具体产品类,实现抽象产品类的接⼝,⼯⼚ 类创建对象,如果有多个需要定义多个
    • IFactory:抽象⼯⼚接口,描述具体⼯⼚的公共接⼝
    • Factory:具体⼯⼚类,实现创建产品类对象,实现抽 象⼯⼚类的接⼝,如果有多个需要定义多个

在这里插入图片描述

要实现工厂方法模式,只需要在原来的简单工厂模式基础上,做出改进,而之前我们创建的IPay抽象产品接口和AliPay WeChatPay 两个具体产品类不需要改动。

首先创建IPayFactory抽象⼯⼚接口:

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 抽象⼯⼚接口
 */
public interface IPayFactory {
    
    
    IPay getPay();
}

然后创建AliPayFactoryWeChatFactory 两个具体⼯⼚类:

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 具体工厂类 AliPayFactory
 */
public class AliPayFactory implements IPayFactory{
    
    
    @Override
    public IPay getPay() {
    
    
        return new AliPay();
    }
}

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 具体工厂类 WeChatFactory
 */
public class WeChatFactory implements IPayFactory{
    
    
    @Override
    public IPay getPay() {
    
    
        return new WeChatPay();
    }
}

进行测试:

@Test
public void testMethodPayFactory(){
    
    
    AliPayFactory aliPayFactory = new AliPayFactory();
    IPay ali_pay = aliPayFactory.getPay();
    ali_pay.unifiedOrder();// 输出:支付宝支付统一下单...
    WeChatFactory weChatFactory = new WeChatFactory();
    IPay wechat_pay = weChatFactory.getPay();
    wechat_pay.unifiedOrder();// 输出:微信支付统一下单...
}
  • 工厂方法模式优点

    • 符合开闭原则,增加⼀个产品类,只需要实现其他具体的产品类和具体的⼯⼚类;

    • 符合单⼀职责原则,每个⼯⼚只负责⽣产对应的产品;

    • 使⽤者只需要知道产品的抽象类,⽆须关⼼其他实现 类,满⾜迪⽶特法则、依赖倒置原则和⾥⽒替换原则;

      • 迪⽶特法则:最少知道原则,实体应当尽量少地与 其他实体之间发⽣相互作⽤;
      • 依赖倒置原则:针对接⼝编程,依赖于抽象⽽不依 赖于具体;
      • ⾥⽒替换原则:俗称LSP, 任何基类可以出现的地 ⽅,⼦类⼀定可以出现, 对实现抽象化的具体步骤的 规范;
  • 工厂方法模式缺点:

    • 增加⼀个产品,需要实现对应的具体⼯⼚类和具体产品类;
    • 每个产品需要有对应的具体⼯⼚和具体产品类;

工厂模式——抽象工厂方法模式

抽象⼯⼚⽅法模式是简单工厂模式 和工厂方法模式的整合升级版

  • ⼯⼚模式有 3 种不同的实现⽅式:

    • 简单⼯⼚模式:通过传⼊相关的类型来返回相应的类,这 种⽅式⽐较单 ⼀,可扩展性相对较差;

    • ⼯⼚⽅法模式:通过实现类实现相应的⽅法来决定相应 的返回结果,这种⽅式的可扩展性⽐较强;

    • 抽象⼯⼚模式:基于上述两种模式的拓展,是⼯⼚⽅法 模式的升级版,当需要创建的产品有多个产品线时使⽤ 抽象⼯⼚模式是⽐较好的选择

    • 抽象⼯⼚模式在 Spring 中应⽤得最为⼴泛的⼀种设计模式

  • 背景:

    • ⼯⼚⽅法模式引⼊⼯⼚等级结构,解决了简单⼯⼚模式 中⼯⼚类职责过重的问题
    • 但⼯⼚⽅法模式中每个⼯⼚只创建⼀类具体类的对象, 后续发展可能会导致⼯⼚类过多,因此将⼀些相关的具 体类组成⼀个“具体类族”,由同⼀个⼯⼚来统⼀⽣产, 强调的是⼀系列相关的产品对象!!!
  • 实现步骤:

    • 1、定义两个接⼝ IPay(支付)、IRefund(退款)
    • 2、创建具体的Pay产品、创建具体的Refund产品
    • 3、创建抽象⼯⼚ IOrderFactory 接⼝ ⾥⾯两个⽅法 createPay/createRefund
    • 4、创建⽀付宝产品族AliOderFactory,实现OrderFactory 抽象⼯⼚
    • 5、创建微信⽀付产品族WechatOderFactory,实现 OrderFactory抽象⼯⼚
    • 6、定义⼀个超级⼯⼚创造器FactoryProducer,通过传递参数获取对应的⼯⼚
      在这里插入图片描述

接下来我们就按照步骤使用一下抽象工厂方法模式:

1、定义两个接⼝ IPay(支付)、IRefund(退款):

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: IPay抽象统一支付下单接口
 */
public interface IPay {
    
    

    /**
     * 统一下单
     */
    void unifiedOrder();
}
package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 退款抽象接口
 */
public interface IReFund {
    
    

    /**
     * 退款
     */
    void refund();
}

2、创建具体的Pay产品、创建具体的Refund产品:

AliPay/WeChatPay:支付宝支付和微信支付

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 具体工厂类 AliPayFactory
 */
public class AliPayFactory implements IPayFactory{
    
    
    @Override
    public IPay getPay() {
    
    
        return new AliPay();
    }
}

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 微信支付具体实现类
 */
public class WeChatPay implements IPay {
    
    
    @Override
    public void unifiedOrder() {
    
    
        System.out.println("微信支付统一下单...");
    }
}

AliRefund/WeChatFund:支付宝退款和微信退款

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description:
 */
public class AliRefund implements IReFund {
    
    
    @Override
    public void refund() {
    
    
        System.out.println("支付宝退款...");
    }
}

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description:
 */
public class WeChatRefund implements IReFund {
    
    
    @Override
    public void refund() {
    
    
        System.out.println("微信支付退款...");
    }
}

3、创建抽象⼯⼚ IOrderFactory 接⼝ ⾥⾯两个⽅法 createPay/createRefund:

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 订单抽象工厂,一个超级工厂可以创建其他工厂(又被称为其他工厂的工厂)
 */
public interface IOrderFactory {
    
    

    IPay createPay();

    IReFund createRefund();
}

4、创建⽀付宝产品族AliOderFactory,实现OrderFactory 抽象⼯⼚:

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description:
 */
public class AliOrderFactory implements IOrderFactory {
    
    
    @Override
    public IPay createPay() {
    
    
        return new AliPay();
    }

    @Override
    public IReFund createRefund() {
    
    
        return new AliRefund();
    }
}

5、创建微信⽀付产品族WechatOderFactory,实现 OrderFactory抽象⼯⼚

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description:
 */
public class WeChatOrderFactory implements IOrderFactory {
    
    
    @Override
    public IPay createPay() {
    
    
        return new WeChatPay();
    }

    @Override
    public IReFund createRefund() {
    
    
        return new WeChatRefund();
    }
}

6、定义⼀个超级⼯⼚创造器FactoryProducer,通过传递参数获取对应的⼯⼚

package com.iswhl.FactoryMethod;

/**
 * @Auther: whl
 * @Date: 2022/8/08/10:00
 * @Description: 工厂创造器
 */
public class FactoryProducer {
    
    

    public static IOrderFactory getFactory(String type){
    
    
        if (type.equalsIgnoreCase("WECHAT")){
    
    
            return new WeChatOrderFactory();
        }else if (type.equalsIgnoreCase("ALI")){
    
    
            return new AliOrderFactory();
        }
        return null;
    }
}

最后我们来进行测试:

package com.iswhl.FactoryMethod;

public class test {
    
    
    public static void main(String[] args) {
    
    
        IOrderFactory wechatPayFactory = FactoryProducer.getFactory("WECHAT");
        wechatPayFactory.createPay().unifiedOrder();
        wechatPayFactory.createRefund().refund();
        IOrderFactory aliPayFactory = FactoryProducer.getFactory("ALI");
        aliPayFactory.createPay().unifiedOrder();
        aliPayFactory.createRefund().refund();
    }
}

结果如下:

微信支付统一下单...
微信支付退款...
支付宝支付 统一下单接口...
支付宝退款...
  • ⼯⼚⽅法模式和抽象⼯⼚⽅法模式

    • 当抽象⼯⼚模式中每⼀个具体⼯⼚类只创建⼀个产品对 象,抽象⼯⼚模式退化成⼯⼚⽅法模式
  • 优点

    • 当⼀个产品族中的多个对象被设计成⼀起⼯作时,它能 保证使⽤⽅始终只使⽤同⼀个产品族中的对象
    • 产品等级结构扩展容易,如果需要增加多⼀个产品等 级,只需要增加新的⼯⼚类和产品类即可, ⽐如增加银 ⾏⽀付、退款
  • 缺点

    • 产品族扩展困难,要增加⼀个系列的某⼀产品,既要在 抽象的⼯⼚和抽象产品⾥修改代码,不是很符合开闭原 则
    • 增加了系统的抽象性和理解难度

猜你喜欢

转载自blog.csdn.net/Ghoul___/article/details/126224996