设计模式- 01 - 工厂方法模式

56 阅读10分钟

设计模式- 01 - 简单工厂

1、设计模式的分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

2、简单工厂模式

2.1 定义:定义一个创建对象的类,由这个类类封装实例化对象的行为

2.2 示例:支付方式

支付工厂一共产生3种支付方式:支付宝支付、微信支付、银联支付 通过工厂类来实例化3种类型的对象

image.png

2.3 代码实现:

  • 抽象产品(Payment 接口) :定义了所有支付方式都需要实现的核心方法(支付、退款、获取支付名称):
// 支付接口(抽象产品)
public interface Payment {
    // 支付方法
    boolean pay(double amount);
    
    // 退款方法
    boolean refund(double amount, String transactionId);
    
    // 获取支付方式名称
    String getPaymentName();
}
  • 具体产品

    • Alipay:支付宝支付实现
    • WechatPay:微信支付实现
    • UnionPay:银联支付实现
      每个具体产品都实现了 Payment 接口,包含各自的支付和退款逻辑

微信支付:

// 微信支付实现(具体产品)
public class WechatPay implements Payment {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用微信支付了 " + amount + " 元");
        // 实际支付逻辑:调用微信支付API等
        return true;
    }

    @Override
    public boolean refund(double amount, String transactionId) {
        System.out.println("微信支付退款 " + amount + " 元,交易ID:" + transactionId);
        // 实际退款逻辑
        return true;
    }

    @Override
    public String getPaymentName() {
        return "微信支付";
    }
}

支付宝支付:

package com.dannie.design.simpleFactory;

// 支付宝实现(具体产品)
public class Alipay implements Payment {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用支付宝支付了 " + amount + " 元");
        // 实际支付逻辑:调用支付宝API等
        return true;
    }

    @Override
    public boolean refund(double amount, String transactionId) {
        System.out.println("支付宝退款 " + amount + " 元,交易ID:" + transactionId);
        // 实际退款逻辑
        return true;
    }

    @Override
    public String getPaymentName() {
        return "支付宝";
    }
}

银联支付:


// 银联支付实现(具体产品)
public class UnionPay implements Payment {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用银联支付了 " + amount + " 元");
        // 实际支付逻辑:调用银联API等
        return true;
    }

    @Override
    public boolean refund(double amount, String transactionId) {
        System.out.println("银联支付退款 " + amount + " 元,交易ID:" + transactionId);
        // 实际退款逻辑
        return true;
    }

    @Override
    public String getPaymentName() {
        return "银联支付";
    }
}
  • 工厂类(PaymentFactory)

    • 提供静态方法 createPayment 根据支付类型字符串创建对应的支付实例
    • 隐藏了具体支付方式的创建细节,客户端只需知道支付类型即可
// 支付工厂类(工厂)
public class PaymentFactory {
    // 根据支付类型创建对应的支付实例
    public static Payment createPayment(String paymentType) {
        if (paymentType == null || paymentType.isEmpty()) {
            return null;
        }

        // 根据支付类型字符串创建对应实例
        switch (paymentType.toLowerCase()) {
            case "alipay":
                return new Alipay();
            case "wechat":
            case "wechatpay":
                return new WechatPay();
            case "unionpay":
            case "union":
                return new UnionPay();
            default:
                throw new IllegalArgumentException("不支持的支付方式: " + paymentType);
        }
    }
}
  • 客户端使用

    • 通过工厂类的静态方法获取支付实例
    • 调用统一的接口方法完成支付或退款操作
    • 无需关心具体支付方式的实现细节

public class PaymentDemo {
    public static void main(String[] args) {
        // 创建支付宝实例并进行支付
        Payment alipay = PaymentFactory.createPayment("alipay");
        if (alipay != null) {
            alipay.pay(199.99);
            alipay.refund(50.0, "ALIPAY123456789");
        }

        // 创建微信支付实例并进行支付
        Payment wechatPay = PaymentFactory.createPayment("wechat");
        if (wechatPay != null) {
            wechatPay.pay(299.50);
        }

        // 创建银联支付实例并进行支付
        Payment unionPay = PaymentFactory.createPayment("unionpay");
        if (unionPay != null) {
            unionPay.pay(599.0);
        }
    }
}

2.4 简单工厂的优点

当需要新增支付方式时,只需添加新的具体产品类并在工厂类中增加对应的创建逻辑,客户端代码不需要任何修改,符合开放 - 封闭原则。同时客户端与具体支付实现解耦,简化了代码维护。

2.4 简单工厂存在的问题与解决方法

简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了开闭原则,所以,从设计角度考虑,有一定的问题,如何解决?我们可以定义一个创建对象的抽象方法并创建多个不同的工厂类实现该抽象方法,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。这种方法也就是我们接下来要说的工厂方法模式。

3、工厂方法模式

3.1 定义:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。

3.2 示例:支付方式

(我们依然举支付方式的例子,不过这个例子中,pizza产地有两个:伦敦和纽约)。添加了一个新的产地,如果用简单工厂模式的的话,我们要去修改工厂代码,并且会增加一堆的if else语句。而工厂方法模式克服了简单工厂要修改代码的缺点,它会直接创建两个工厂,纽约工厂和伦敦工厂。类图如下:

3.3 代码实现:

  • 抽象产品(Payment):定义产品的公共接口
// 支付接口(抽象产品)
public interface Payment {
    // 支付方法
    void pay(double amount);

    // 退款方法
    void refund(double amount, String tradeNo);

    // 获取支付方式名称
    String getPaymentName();
}
  • 具体产品(Alipay、WechatPay、UnionPay):实现抽象产品接口
// 支付宝实现(具体产品)
class AliPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付了 " + amount + " 元");
        // 实际支付逻辑:调用支付宝API等
    }

    @Override
    public void refund(double amount, String tradeNo) {
        System.out.println("支付宝退款 " + amount + " 元,交易号:" + tradeNo);
        // 实际退款逻辑
    }

    @Override
    public String getPaymentName() {
        return "支付宝";
    }
}
// 银联支付实现(具体产品)
public class UnionPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用银联支付了 " + amount + " 元");
        // 实际支付逻辑:调用银联API等
    }

    @Override
    public void refund(double amount, String tradeNo) {
        System.out.println("银联支付退款 " + amount + " 元,交易号:" + tradeNo);
        // 实际退款逻辑
    }

    @Override
    public String getPaymentName() {
        return "银联支付";
    }
}
// 微信支付实现(具体产品)
public class WechatPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付了 " + amount + " 元");
        // 实际支付逻辑:调用微信支付API等
    }

    @Override
    public void refund(double amount, String tradeNo) {
        System.out.println("微信支付退款 " + amount + " 元,交易号:" + tradeNo);
        // 实际退款逻辑
    }

    @Override
    public String getPaymentName() {
        return "微信支付";
    }
}
  • 抽象工厂(PaymentFactory):定义创建产品的接口
// 支付工厂接口(抽象工厂)
public interface PaymentFactory {
    Payment createPayment();
}
  • 具体工厂(AlipayFactory 等):实现抽象工厂接口,负责创建对应的具体产品
// 支付宝工厂(具体工厂)
public class AlipayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        // 可以在这里添加支付宝支付所需的初始化逻辑
        return new AliPay();
    }
}
// 银联支付工厂(具体工厂)
public class UnionPayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        // 可以在这里添加银联支付所需的初始化逻辑
        return new UnionPay();
    }
}
// 微信支付工厂(具体工厂)
public class WechatPayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        // 可以在这里添加微信支付所需的初始化逻辑
        return new WechatPay();
    }
}

3.4 与简单工厂模式的区别

  • 工厂方法模式为每种产品提供了专门的工厂类
  • 新增产品时,只需添加新的具体产品类和对应的具体工厂类
  • 无需修改现有工厂代码,完全符合开闭原则

3.5优点

  • 降低了耦合度,客户端只需关心抽象接口
  • 扩展性好,新增支付方式无需修改原有代码
  • 单一职责原则,每个工厂只负责创建一种产品

3.6 工厂方法存在的问题与改进

工厂方法存在的问题与解决方法:客户端需要创建类的具体的实例。简单来说就是用户要支付宝工厂支付,他必须支付宝工厂,想微信支付必须使用微信支付工厂。 当支付宝工厂和微信工厂发生变化了,用户也要跟着变化,这无疑就增加了用户的操作复杂性。为了解决这一问题,我们可以把工厂类抽象为接口,用户只需要去找默认的工厂提出自己的需求(传入参数),便能得到自己想要产品,而不用根据产品去寻找不同的工厂,方便用户操作。这也就是我们接下来要说的抽象工厂模式。

4、抽象工厂模式

4.1 定义:定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类。

4.2 示例:支付方式

(我们依然举支付方式的例子,不过这个例子中,pizza产地有两个:伦敦和纽约)。添加了一个新的产地,如果用简单工厂模式的的话,我们要去修改工厂代码,并且会增加一堆的if else语句。而工厂方法模式克服了简单工厂要修改代码的缺点,它会直接创建两个工厂,纽约工厂和伦敦工厂。类图如下:

4.3 代码实现:

  • 抽象产品族:
// 支付抽象产品接口
public interface Payment {
    // 处理支付
    String process(double amount);
    // 获取支付平台名称
    String getPlatformName();
}
    
// 退款抽象产品接口
public interface Refund {
    // 处理退款
    String process(double amount, String transactionId);
}
    
// 交易查询抽象产品接口
public interface TransactionQuery {
    // 查询交易状态
    String queryStatus(String transactionId);
    // 查询交易详情
    String queryDetails(String transactionId);
}

  • 具体产品:
    • 支付宝系列产品:
// 支付宝支付具体产品
public class AlipayPayment implements Payment {
    @Override
    public String process(double amount) {
        String transactionId = "ALIPAY" + System.currentTimeMillis();
        return String.format("支付宝支付成功,金额: %.2f元,交易ID: %s", amount, transactionId);
    }
    
    @Override
    public String getPlatformName() {
        return "支付宝";
    }
}

// 支付宝退款具体产品
public class AlipayRefund implements Refund {
    @Override
    public String process(double amount, String transactionId) {
        return String.format("支付宝退款成功,金额: %.2f元,原交易ID: %s", amount, transactionId);
    }
}

// 支付宝系统具体工厂
public class AlipaySystemFactory implements PaymentSystemFactory {
    @Override
    public Payment createPayment() {
        return new AlipayPayment();
    }
    
    @Override
    public Refund createRefund() {
        return new AlipayRefund();
    }
    
    @Override
    public TransactionQuery createTransactionQuery() {
        return new AlipayTransactionQuery();
    }
}

- 微信系列产品:
// 微信支付具体产品
public class WechatPayment implements Payment {
    @Override
    public String process(double amount) {
        String transactionId = "WECHAT" + System.currentTimeMillis();
        return String.format("微信支付成功,金额: %.2f元,交易ID: %s", amount, transactionId);
    }
    
    @Override
    public String getPlatformName() {
        return "微信支付";
    }
}

// 微信退款具体产品
public class WechatRefund implements Refund {
    @Override
    public String process(double amount, String transactionId) {
        return String.format("微信退款成功,金额: %.2f元,原交易ID: %s", amount, transactionId);
    }
}

// 微信交易查询具体产品
public class WechatTransactionQuery implements TransactionQuery {
    @Override
    public String queryStatus(String transactionId) {
        return String.format("微信交易 %s 状态: 已支付", transactionId);
    }
    
    @Override
    public String queryDetails(String transactionId) {
        return String.format("微信交易 %s 详情: { 状态: 成功, 支付方式: 微信零钱, 时间: %s }", 
                transactionId, java.time.LocalDateTime.now());
    }
}

  • 抽象工厂
// 支付系统抽象工厂接口
public interface PaymentSystemFactory {
    Payment createPayment();
    Refund createRefund();
    TransactionQuery createTransactionQuery();
}
  • 具体工厂:
// 支付宝系统具体工厂
public class AlipaySystemFactory implements PaymentSystemFactory {
    @Override
    public Payment createPayment() {
        return new AlipayPayment();
    }
    
    @Override
    public Refund createRefund() {
        return new AlipayRefund();
    }
    
    @Override
    public TransactionQuery createTransactionQuery() {
        return new AlipayTransactionQuery();
    }
}


// 微信支付系统具体工厂
public class WechatPaySystemFactory implements PaymentSystemFactory {
    @Override
    public Payment createPayment() {
        return new WechatPayment();
    }
    
    @Override
    public Refund createRefund() {
        return new WechatRefund();
    }
    
    @Override
    public TransactionQuery createTransactionQuery() {
        return new WechatTransactionQuery();
    }
}
    

  • 客户端:

    • 通过选择不同的具体工厂,获得一整套相关的产品
    • 无需知道具体实现,只需通过抽象接口操作
// 客户端使用示例
public class PaymentClient {
    public static void main(String[] args) {
        // 使用支付宝支付系统
        System.out.println("=== 使用支付宝支付系统 ===");
        PaymentSystemFactory alipayFactory = new AlipaySystemFactory();
        Payment alipay = alipayFactory.createPayment();
        String alipayResult = alipay.process(199.99);
        System.out.println(alipayResult);
        
        // 提取交易ID用于后续操作
        String alipayTransactionId = alipayResult.split("交易ID: ")[1];
        
        Refund alipayRefund = alipayFactory.createRefund();
        System.out.println(alipayRefund.process(50.0, alipayTransactionId));
        
        TransactionQuery alipayQuery = alipayFactory.createTransactionQuery();
        System.out.println(alipayQuery.queryStatus(alipayTransactionId));
        System.out.println(alipayQuery.queryDetails(alipayTransactionId));
        
        // 使用微信支付系统
        System.out.println("\n=== 使用微信支付系统 ===");
        PaymentSystemFactory wechatFactory = new WechatPaySystemFactory();
        Payment wechatPay = wechatFactory.createPayment();
        String wechatResult = wechatPay.process(299.50);
        System.out.println(wechatResult);
        
        String wechatTransactionId = wechatResult.split("交易ID: ")[1];
        
        TransactionQuery wechatQuery = wechatFactory.createTransactionQuery();
        System.out.println(wechatQuery.queryStatus(wechatTransactionId));
    }
}
    

4.4、抽象工厂模式的优势

  • 产品族一致性:确保同一工厂创建的产品能够协同工作
  • 隔离具体实现:客户端面向抽象接口编程,无需关心具体实现类
  • 易于切换产品系列:更换具体工厂即可切换整个产品系列
  • 符合开闭原则:新增支付平台只需添加新的具体工厂和产品,无需修改现有代码 如果需要添加新的支付方式(如银联支付),只需创建对应的具体产品类和具体工厂类,客户端代码无需任何修改。