工厂三件套
三种工厂对比
简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象; 工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量
if-else
判断; 抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
场景1:发奖
目标:多类型产品,统一发奖接口
大致过程
套模板(虽然傅哥说不让硬套)
- 如果看成简单工厂的话:
简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象
StoreFactory
是唯一的工厂类,ICommodity
是产品抽象类,XXXService
是具体的产品,工厂类StoreFactory
根据入参创建对应的发奖服务对象
- 如果看成工厂方法的话:
工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量if-else
判断
这里把ICommodity
看成父类,ICommodity
规定了发奖的标准方法sendCommodity(...)
,XXXService
看成多个子工厂,子工厂各自的发奖类型由子类自己决定。(缺少了产品抽象类?产品类型体现在入参里,所以发奖结果没有返回值,也不需要返回值
场景2:Redis集群升级
目标:将单机Redis升级到双集群,其中每个集群拥有不同的调用方法
铺垫:JDK代理的使用
- 目的:通过JDK代理相应的接口,实现对接口方法的升级和改造
- 代理对象如何生成:
通过静态方法Proxy#nexProxyInstance(类加载器,A接口.class,InvocationHandler对象)
返回一个实现了A接口的代理对象,其中invocationHandler对象
的invoke方法
控制了接口方法的改造 - 代理对象是如何起作用的:
代理对象proxy
每次调用方法时,都会进入到invocationHandler#invoke(...)
里,invocationHandler#invoke(...)
的返回值就是该方法的返回值。在实现的InvocationHandler#invoke(..)
里,一般会有一行method.invoke(...)
的代码,这是方法真正的调用,而在其前后添加处理逻辑可以实现方法外部功能扩展,也可以直接对method
做改动实现方法内部的升级改造~
- Redis升级双集群的大概过程:
- 用适配器包装组合同一类型的产品,统一Redis集群的接口方法
- 生成原本地redis服务的代理对象
1)实现InvocationHanlder
类- 将用适配器包装好的redis集群对象通过构造器注入到
InvocationHandler
里,等待使用 - 实现
InvocationHandler#invoke()
方法,每次调用原接口方法时自动替换为新redis集群的方法
- 将用适配器包装好的redis集群对象通过构造器注入到
2)使用静态方法生成代理对象
- `Proxy.newProxyInstance(类加载器,代理的原接口,上一步实现的Invocationhandler类)`
- 使用该代理对象替换原来的服务
- 总结:子工厂拥有统一的生产方法,单个子工厂可以生产多个代理对象,这些可生产的类型通过适配器组合控制
最秒的地方在于用适配器包装新redis集群,使得redis集群接口和原redis单机接口拥有相似的方法参数,在代理方法改造时可以方便的替换
自己的总结
- 简单工厂:只有一个工厂,根据入参类型直接产出产品
- 工厂方法:一个父工厂,根据入参类型生成一堆子工厂干活,这些子工厂干活时调用的方法一样,每个子工厂只能产出一种类型的产品
- 抽象工厂:一个父工厂,根据入参类型生成一堆子工厂干活,这些子工厂干活时调用的方法一样,但每个子工厂可以产出一种或多种类型的产品(可通过适配器组合)