工厂三件套

三种工厂对比

简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象; 工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量if-else判断; 抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。

image-20220317212651582.png


场景1:发奖

  • 目标:多类型产品,统一发奖接口

  • 大致过程

image-20220317210739344.png

  • 套模板(虽然傅哥说不让硬套)

    • 如果看成简单工厂的话:

简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象

StoreFactory是唯一的工厂类,ICommodity是产品抽象类,XXXService是具体的产品,工厂类StoreFactory根据入参创建对应的发奖服务对象

  • 如果看成工厂方法的话:

工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量if-else判断

这里把ICommodity看成父类,ICommodity规定了发奖的标准方法sendCommodity(...)XXXService看成多个子工厂,子工厂各自的发奖类型由子类自己决定。(缺少了产品抽象类?产品类型体现在入参里,所以发奖结果没有返回值,也不需要返回值
image-20220318164428211.png


场景2:Redis集群升级

  • 目标:将单机Redis升级到双集群,其中每个集群拥有不同的调用方法

  • 铺垫:JDK代理的使用

    • 目的:通过JDK代理相应的接口,实现对接口方法的升级和改造
    • 代理对象如何生成:
      通过静态方法Proxy#nexProxyInstance(类加载器,A接口.class,InvocationHandler对象)返回一个实现了A接口的代理对象,其中invocationHandler对象invoke方法控制了接口方法的改造
    • 代理对象是如何起作用的:
      代理对象proxy每次调用方法时,都会进入到invocationHandler#invoke(...)里,invocationHandler#invoke(...)的返回值就是该方法的返回值。在实现的InvocationHandler#invoke(..)里,一般会有一行method.invoke(...)的代码,这是方法真正的调用,而在其前后添加处理逻辑可以实现方法外部功能扩展,也可以直接对method做改动实现方法内部的升级改造~
      image-20220319195203833.png
  • Redis升级双集群的大概过程
    1. 用适配器包装组合同一类型的产品,统一Redis集群的接口方法
    2. 生成原本地redis服务的代理对象
      1)实现InvocationHanlder
      • 将用适配器包装好的redis集群对象通过构造器注入到InvocationHandler里,等待使用
      • 实现InvocationHandler#invoke()方法,每次调用原接口方法时自动替换为新redis集群的方法

2)使用静态方法生成代理对象

  1. - `Proxy.newProxyInstance(类加载器,代理的原接口,上一步实现的Invocationhandler类)`
  1. 使用该代理对象替换原来的服务

image-20220319212234170.png

  • 总结:子工厂拥有统一的生产方法,单个子工厂可以生产多个代理对象,这些可生产的类型通过适配器组合控制
    最秒的地方在于用适配器包装新redis集群,使得redis集群接口和原redis单机接口拥有相似的方法参数,在代理方法改造时可以方便的替换
    image-20220319204911922.png

自己的总结

  • 简单工厂:只有一个工厂,根据入参类型直接产出产品
  • 工厂方法:一个父工厂,根据入参类型生成一堆子工厂干活,这些子工厂干活时调用的方法一样,每个子工厂只能产出一种类型的产品
  • 抽象工厂:一个父工厂,根据入参类型生成一堆子工厂干活,这些子工厂干活时调用的方法一样,但每个子工厂可以产出一种或多种类型的产品(可通过适配器组合)