Java工厂设计模式详解

前言

工厂设计模式在开发过程中有大量的运用,不管是spring框架,还是诸多的中间件,都有着工厂设计模式的体现

比如,手机生产工厂,当提供了相关生产手机的原材料,工厂就可以按要求生产出手机

在这里插入图片描述

工厂模式介绍

工厂模式提供了一种创建对象的最佳方式,我们在创建对象的时候不会对客户端暴露具体的创建对象的逻辑,并通过使用一个共同创建的接口来指向新创建的对象

工厂模式常用实现方式

  • 简单工厂模式
    通过传入相关的类型参数来返回相应的类,这是最简单的一种实现方式,功能相对单一,ke扩展性较差

  • 工厂方法模式
    通过实现类实现相应的方法来决定相应的返回结果,这种方式的扩展性相对上面一种有较大提升

  • 抽象工厂模式
    基于上面两种方式的拓展,并且支持细化产品

工厂模式的应用场景及好处

  • 代码解耦
    职责分离,把复杂对象的创建和使用的过程分开
  • 代码复用,降低维护成本
    如果创建对象的过程比较复杂并且多处使用,假如每个使用的地方都需要重写一遍,将会产生很多重复代码,一旦业务逻辑发生变更,修改代码的地方就会很多,而使用工厂模式统一创建,只需要修改工厂类即可

下面通过代码实例演示下3种方式的实现过程

1、简单工厂模式

  1. 又称为静态工厂方法,可以根据参数的不同返回不同类的实例,需要专门定义一个类用于创建其他类的实例,被创建的类的实例通常具有共同的父类
  2. 由于工厂方法是静态方法,可以通过类名直接调用,而且只需要传入简单的参数即可

核心组成

  • Factory:工厂类,简单工厂模式的核心,负责实现创建所有实例的内部逻辑
  • IProduct:抽象产品类,简单工厂模式所创建的所有对象的父类,这里可理解为所有实例的公共接口或抽象类
  • ProductL具体产品类,简单工厂模式的创建目标

以一个实际的业务场景为例,某个业务需要对接各个主流的支付平台,假如需要后台支持支付宝,微信,银联3种甚至更多的支付方式,实际客户端调用的时候,希望做到根据传入某种支付类型就可以达到使用该支付方式支付的目的,这里尝试使用简单工厂模式进行实现

在这里插入图片描述

定义抽象产品支付接口Pay

/**
 * 抽象产品
 */
public interface Pay {

    /**
     * 统一下单接口
     */
    void unionPay();

}

具体的产品类,这里包括3种,支付宝,微信,银联,即3种类型的具体的业务实现,这里叫做具体的产品类

支付宝,微信,银联

public class AliPay implements Pay {
    @Override
    public void unionPay() {
        System.out.println("this is ali pay");
    }
}
public class WeChatPay implements Pay {
    @Override
    public void unionPay() {
        System.out.println("this is wechat pay");
    }
}
public class BankPay implements Pay {
    @Override
    public void unionPay() {
        System.out.println("this is bank pay");
    }
}

简单工厂,根据支付类型返回相应的支付实现

/**
 * 统一支付工厂类,根据传入的支付类型返回相应的支付方式
 */
public class SimplePayFactory {

    public static Pay getPay(String type){
        switch (type){
            case "aliPay":
                return new AliPay();
            case "weChatPay":
                return new WeChatPay();
            case "bankPay":
                return new BankPay();
             default:
                 return null;
        }
    }

}

测试类:

public class Test {

    public static void main(String[] args) {
        Pay weChatPay = SimplePayFactory.getPay("weChatPay");
        weChatPay.unionPay();;
    }

}

在这里插入图片描述

当尝试传入不同的type时,可以输出不同的结果,这就是简单工厂的实现,当然,具体在开发中,每种支付内部的业务是远远比上面的逻辑要复杂的

优点:

  • 将对象的创建和对象本身业务处理进行分离,一定程度上降低了系统的耦合性,这样一来当某种具体的支付产品发生变化时,修改起来相对简单

缺点:

  • 工厂职责相对单一,并且过重,新增加产品时需要修改工厂类的内部逻辑,这与开闭原则是相违背的
  • 当新增更多产品时,一定程度上会增加系统中类的个数,从而增加了系统的复杂度和理解难度,不利于系统的扩展和维护

2、工厂方法模式

  • 又称工厂模式,是对简单工厂的进一步抽象,好处是可以使得系统在不修改原来代码情况下引进新的产品,满足开闭原则
  • 通过工厂父类定义创建产品的公共接口,通过子类确定所需要创建的类型
  • 相比简单工厂,此模式具备更多的可扩扩展性和可复用性,同时也增强了代码的可读性
  • 将类的实例化(具体产品的创建)延迟到工厂类的子类完成,即由子类决定应该实例化哪一个类

用一张图简单解释下工厂方法模式下各个组件的位置

在这里插入图片描述

  • IProduct:抽象产品类,定义和描述所有产品的公共接口
  • Product:具体的产品类,比如这里的阿里支付,微信支付和银联支付
  • IFactory:抽象工厂类,描述具体实例工厂的公共接口
  • Factory:具体工厂,具体实现创建产品类对象的工厂,实际可能有多个

可以结合上图对工厂方法模式中的各个组件进行理解,下面结合具体的代码进行说明

复用简单工厂模式中的3种产品的代码,只需要定义右半边的部分代码即可

定义抽象产品工厂

public interface PayFactory {
    Pay getPay();
}

产出各个具体产品的工厂,比如对应这里aliPay,weChatPay,bankPay的3个工厂

public class AliPayFactory implements PayFactory {
    @Override
    public Pay getPay() {
        return new AliPay();
    }
}
public class WechatPayFactory implements PayFactory {
    @Override
    public Pay getPay() {
        return new WeChatPay();
    }
}
public class BankPayFactory implements PayFactory {
    @Override
    public Pay getPay() {
        return new BankPay();
    }
}

测试类

public class FactoryTest {

    public static void main(String[] args) {
        PayFactory factory = new AliPayFactory();
        Pay pay = factory.getPay();
        pay.unionPay();
    }
}

在这里插入图片描述

可以通过new不同产品的工厂达到使用不同支付方式的目的

优点:

  • 增加一个产品类,只需要实现其他具体的产品类和具体的产品工厂类即可
  • 符合职责单一的原则,每个工厂只负责生产对应的产品
  • 使用者只需要知道产品的抽象接口即可,无须关心其他的实现类

缺点:

  • 增加一个产品,需要实现具体的产品类和具体的产品工厂
  • 每个产品都要有对应的工厂和具体的产品类

3、抽象工厂模式

  • 基于上述2种模式的拓展,属于工厂方法模式的升级版,当需要创建的产品存在多个产品线时可以考虑使用抽象工厂模式
  • 抽象工厂模式在spring框架中使用非常广泛

在上面的两种模式中,总结各自的优缺点,不难发现下面2点问题:

  • 工厂方法模式引入了工厂等级,解决了简单工厂模式中工厂类职责过重的问题
  • 但是工厂方法中每个工厂只针对某一个具体的产品,后续随着业务的拓展,可能导致工厂类过多,因此如果可以考虑将一些相关的具体类组成一个“类产品簇”,由同一个工厂统一生产,就可以减少工厂的创建,而抽象工厂模式正是基于这个思想,强调的是一系列相关产品的对象

何谓产品簇,可以理解为,手机厂商不仅可以代工安卓手机,还能代工苹果手机,甚至老人机等,这样一来,手机代工厂的职责相比只生产某种类型的手机就更强大了

在这里插入图片描述

按照上图所示的步骤,下面开始编写具体的代码进行实现

业务场景:在实际的订单场景中,涉及到两个操作,订单支付和支付对账,即createPay和checkPay,这两种业务,不管是支付宝还是微信,或者是其他支付平台,都可以进行操作

以此我们假定超级工厂(顶级父工厂)具备这两种业务能力,而对应的各个支付平台,它们也需要这两种业务产品的能力实现,按照上图,即支付宝和微信会有各自的业务对应的工厂,即AliOrderFactory 和WeChatOrderFactory,

1、定义超级工厂和业务工厂,持有各个业务的具体能力,这里理解为支付createPay和对账checkPay

/**
 * 支付对账
 */
public interface CheckFactory {
    void checkPay();
}
/**
 * 支付工厂
 */
public interface PayFactory {
    void createPay();
}
/**
 * 超级工厂
 */
public interface OrderFactory {
    PayFactory createPay();
    
    CheckFactory createCheck();
}

2、定义支付宝自身的产品工厂和具体实现


/**
 * 支付宝对账产品实现
 */
public class AliCheck implements CheckFactory {

    @Override
    public void checkPay() {
        System.out.println("ali checkPay ,阿里支付对账");
    }
}
/**
 * 支付宝支付产品实现
 */
public class AliPay implements PayFactory {
    @Override
    public void createPay() {
        System.out.println("ali createPay ,阿里支付");
    }
}
/**
 * 支付宝工厂,对外输出的产品能力
 */
public class AliOrderFactory implements OrderFactory {

    @Override
    public PayFactory createPay() {
        return new AliPay();
    }

    @Override
    public CheckFactory createCheck() {
        return new AliCheck();
    }

}

3、定义微信自身的产品工厂和具体实现

public class WeChatCheck implements CheckFactory {

    @Override
    public void checkPay() {
        System.out.println("wechat checkPay ,微信支付对账");
    }
}
public class WeChatPay implements PayFactory {
    @Override
    public void createPay() {
        System.out.println("WeChatPay createPay ,微信支付");
    }
}
public class WeChatOrderFactory implements OrderFactory {

    @Override
    public PayFactory createPay() {
        return new WeChatPay();
    }

    @Override
    public CheckFactory createCheck() {
        return new WeChatCheck();
    }

}

从上面的代码结构不难发现,在实际业务中,各个具体的支付平台都有自身的复杂的产品实现,比较好的方式就像上面的支付工厂,屏蔽掉底层的所有实现细节,客户都安只需要调用工厂找到相关的实现即可

4、提供一个工厂建造器,用于提供不同平台的支付工厂

/**
 * 工厂建造器
 */
public class FactoryBuilder {

    public static OrderFactory getFactory(String type){
        switch (type){
            case "aliPay":
                return new AliOrderFactory();
            case "weChatPay":
                return new WeChatOrderFactory();
             default:
                 return null;
        }
    }
}

最后提供一个简单的测试类

public class FactoryTest {

    public static void main(String[] args) {
        OrderFactory aliPay = FactoryBuilder.getFactory("aliPay");
        aliPay.createPay().createPay();
    }

}

在这里插入图片描述

同时可以看到,抽象工厂设计模式从某种意义上,相当于是结合了前面两种模式的优点,可以说,抽象工厂模式并不是完全独立的一种模式

具体来说,优点:

  • 当一个产品簇中的多个对象被设计成一起工作时,它能保证使用的方法始终是同一个产品簇中的对象
  • 产品等级结构容易扩展,如果需要增加多更多的产品等级,只需要增加新的工厂类和产品类即可,比如增加银联支付等

缺点:

  • 产品簇扩展困难,要在某个系列中增加一个产品,需要同时在抽象工厂和抽象产品修改代码,不是很符合开闭原则
  • 增加了系统整体上的抽象性和理解上的难度,从代码的结构层次上可以发现这个问题
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小码农叔叔

谢谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值