原创

设计模式之工厂模式

温馨提示:
本文最后更新于 2023年11月16日,已超过 433 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

工厂模式

工厂模式是Java中最常用的设计模式之一。它属于创建型模式,通过工厂方式来替代new操作,以封装和管理对象的创建。在Java中,工厂模式常被用于创建具有相同接口或基类的对象,但具有不同实现或配置的实例。

工厂模式可分为:简单/静态工厂模式、工厂方法模式、抽象工厂模式三种。本文将一一介绍三种工厂模式的应用场景及其优缺点。

为什么要用工厂模式?

首先,我没来理解一下什么场景下可以使用工厂模式,以及使用工厂模式后有何好处。

场景

假设,公司做一个电商系统,需要对接不同支付渠道,比如:支付宝支付、微信支付、银行卡卡扣、会员卡卡扣等等。当用户选择不同支付渠道时,系统需要通过不同渠道来进行支付,执行不同支付渠道的业务逻辑。

如果采用硬编码方式,我们只需要在支付时进行判断用户选择的渠道,并处理相关业务即可。当有新的支付渠道需要对接时,此时我们就需要继续添加条件判断,并在原代码写相关业务逻辑。

此时,不仅我们的代码显得臃肿,且在任意支付渠道业务产生变动而需要改动相关代码时,有可能影响到其他支付渠道业务逻辑,凭空增加了更多工作量和风险。这时候,如果我们使用合适的设计来规避这些问题,不仅代码显得美丽,降低耦合度,更让系统变得更加健壮。

1.简单/静态工厂模式

简单/静态工厂模式是最简单的模式,仅将对象创建进行了简单封装,通过向工厂传递类型来指定要创建的对象。

1.1 编写支付接口

public interface Pay {
    String pay();
}

1.2 编写支付逻辑

public class AlipayPay implements Pay {
    @Override
    public String pay() {
        return "调用阿里支付成功!";
    }
}
public class WeChatPay implements Pay{
    @Override
    public String pay() {
        return "调用微信支付成功!";
    }
}

1.3 创建工厂

public class PayFactory {
    public Pay pay(String channel) {
        Pay pay = null;
        if (Objects.equals("alipay", channel)){
            pay = new AlipayPay();
        } else if (Objects.equals("weChat", channel)){
            pay = new WeChatPay();
        }
        return pay;
    }
}

1.4 使用工厂来实现业务逻辑

public static void main(String[] args) {
        PayFactory payFactory = new PayFactory();
        Pay alipay = payFactory.pay("alipay");
        String alipayResult = alipay.pay();
        System.out.println(alipayResult); // 调用阿里支付成功!

        Pay weChat = payFactory.pay("weChat");
        String weChatResult = weChat.pay();
        System.out.println(weChatResult); // 调用微信支付成功!
    }

1.5 优缺点

优点:

  • 简单易懂,代码量小
  • 避免了调用方和实现方的耦合

缺点:

  • 扩展性差,添加新的支付渠道,需要修改工厂方法及调用方代码,不符合开闭原则。
  • 对象创建逻辑没有抽象化,可维护性差
  • 当工厂出现bug时,整个逻辑将会崩溃

2 工厂方法模式

工厂方法模式进一步将对象的创建和使用进行解耦。它定义了一个工厂接口,不再提供统一工厂来创建所有产品,而是将负责生成具体产品的任务分发给具体的产品工厂。

2.1 抽象化工厂

public interface PayFactory {
    Pay initPay();
}

2.2 实现业务工厂逻辑

public class AlipayPayFactory implements PayFactory{
    @Override
    public Pay initPay() {
        return new AlipayPay();
    }
}
public class WeChatPayFactory implements PayFactory{
    @Override
    public Pay initPay() {
        return new WeChatPay();
    }
}

2.3 使用

public static void main(String[] args) {
        PayFactory alipayFactory = new AlipayPayFactory();
        Pay alipay = alipayFactory.initPay();
        String alipayResult = alipay.pay();
        System.out.println(alipayResult);

        PayFactory weChatFactory = new WeChatPayFactory();
        Pay weChat = weChatFactory.initPay();
        String weChatResult = weChat.pay();
        System.out.println(weChatResult);
    }

2.4 优缺点

优点:

  • 扩展性好:添加新的支付渠道时增加新的工厂类即可,不改变原有代码。符合开闭原则。

缺点:

  • 代码量增大:需要定义工厂接口和实现类。
  • 如果工厂类很多,代码结构变得复杂。

3 抽象工厂模式

抽象工厂为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。通过抽象工厂模式,将客户端与具体的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。

例如:当调用支付后,我们要查询支付结果,此时需要先定义一个结果查询接口,并依次实现各渠道查询逻辑;当调用某一渠道支付业务后,稍后需要查询当前渠道的支付结果,而不能查询到其他渠道。

在这个例子中,支付和结果查询两个业务是相互匹配绑定的,不能出现交叉的情况。

3.1 定义查询支付结果接口

public interface Result {
    String result();
}

3.2 实现查询逻辑

public class AlipayResult implements Result{
    @Override
    public String result() {
        return "通过阿里支付付款成功!";
    }
}
public class WeChatResult implements Result{
    @Override
    public String result() {
        return "通过微信支付付款成功!";
    }
}

3.3 定义抽象工厂类

public abstract class AbstractFactory {
    public abstract Pay pay();
    public abstract Result result();
}

3.4 实现工厂逻辑

public class AlipayFactory extends AbstractFactory{
    @Override
    public Pay pay() {
        return new AlipayPay();
    }

    @Override
    public Result result() {
        return new AlipayResult();
    }
}
public class WeChatFactory extends AbstractFactory{
    @Override
    public Pay pay() {
        return new WeChatPay();
    }

    @Override
    public Result result() {
        return new WeChatResult();
    }
}

3.5 使用

public static void main(String[] args) {
        AbstractFactory alipayFactory = new AlipayFactory();
        Pay alipay = alipayFactory.pay();
        String pay = alipay.pay();
        Result alipayResult = alipayFactory.result();
        String result = alipayResult.result();
        System.out.println(pay); // 调用阿里支付成功!
        System.out.println(result); // 通过阿里支付付款成功!

        AbstractFactory weChatFactory = new WeChatFactory();
        Pay weChat = weChatFactory.pay();
        String pay2 = weChat.pay();
        Result weChatResult = weChatFactory.result();
        String result2 = weChatResult.result();
        System.out.println(pay2); // 调用微信支付成功!
        System.out.println(result2); // 通过微信支付付款成功!
    }

3.6 优缺点:

优点:

  • 当一个产品族中多个对象被设计成一起工作时,他能保证客户端始终只使用同一个产品族中的对象。
  • 当增加新的支付渠道时,只需要实现当前业务逻辑即可。

缺点:

  • 产品族扩展困难,要增加族中产品时,既要抽象创建代码,又要实现具体代码。因此适合业务稳定,不会频繁增减业务的场景。
    例如:支付接口改版为先下单,下单成功再支付,然后再获取支付结果,那么所有的产品族都需要改动。
正文到此结束
本文目录