工厂模式介绍
工厂模式也称简单工厂模式,是创建型设计模式的一种,这种设计模式提供了按需创建对象的最佳方式。同时,这种创建方式不会对外暴露创建西街,并且会通一个统一的接口创建所需对象。
这种设计模式也是Java开发中常见的一种模式,它的主要意图是定义一个创建对象的接口,让其子类自己决定将哪个工厂类实例化,工厂模式使创建过程延迟到子类中进行。
简单的说,就是为了给代码结构提供扩展性,屏蔽每一个功能类中的具体实现逻辑。这种方式便于外部更简单地调用,同时也是去掉众多if···else的最佳手段。当然,这种设计模式也有一些缺点,需要治理。例如实现的类比较多、难以维护、开发成本高等,但这些问题都可以通过结合不同的设计模式逐步解决。
工厂模式的简单使用
在这里就举例一种在业务中常见的一种情况,if else大法,每次我看到代码一堆的if else我就感到头痛,虽然if else 用起来确实十分的香,而且实现业务需求十分的快速便捷,但是当维护起来简直就是噩梦。万一自己写的if else 大法交给别人来维护,我怕有人对我施展C语言。
需求:模拟发放多个产品,这里根据不同的类型兑换不同的奖励,类型当然有多种多样,比如优惠券、实体商品、第三方的兑换卡(爱奇艺会员、腾讯会员等等)。
违背设计模式实现
来我们先看最简单实现方式(不得不说在业务中,我经常这样写)
1、我们先定义一个入参类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | package bestrookie.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
 
 
 
  @Data @AllArgsConstructor @NoArgsConstructor public class AwardReq {     private Integer id;     private String userName;     private Integer type; }
   | 
 
2、然后我们根据奖励的类型写不同的兑换奖品的逻辑(具体的业务逻辑就不实现了)
优惠券:
1 2 3 4 5 6 7 8 9 10 11
   | package bestrookie.service; import bestrookie.pojo.AwardReq;
 
 
 
  public class CouponService {     public void send(AwardReq awardReq){         System.out.println("发放优惠券====》"+awardReq.getUserName());     } }
   | 
 
实体商品:
1 2 3 4 5 6 7 8 9 10 11
   | package bestrookie.service; import bestrookie.pojo.AwardReq;
 
 
 
  public class GoodService {     public void send(AwardReq awardReq){         System.out.println("发送实体商品===》"+awardReq.getUserName());     } }
   | 
 
三方兑换卡:
1 2 3 4 5 6 7 8 9 10 11
   | package bestrookie.service; import bestrookie.pojo.AwardReq;
 
 
 
  public class QiYiUserService {     public void send(AwardReq awardReq){         System.out.println("爱奇艺兑换码====》"+awardReq.getUserName());     } }
   | 
 
3、然后就是根据类型调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | package bestrookie.controller; import bestrookie.pojo.AwardReq; import bestrookie.service.CouponService; import bestrookie.service.GoodService; import bestrookie.service.QiYiUserService;
 
 
 
  public class PrizeController {     public static void main(String[] args) {         AwardReq awardReq = new AwardReq(1,"bestrookie",1);         if (awardReq.getType() == 1){             CouponService couponService = new CouponService();             couponService.send(awardReq);         }else if (awardReq.getType() == 2){             GoodService goodService = new GoodService();             goodService.send(awardReq);         }else if (awardReq.getType() == 3){             QiYiUserService qiYiUserService = new QiYiUserService();             qiYiUserService.send(awardReq);         }         System.out.println("========发放完成=========");     } }
   | 
 
这个if else 是不是十分的经典,这样代码虽然看起来并不是很多,但是这也是我们各种业务的逻辑都省略了,所以看起来代码少,在真实业务中中间还有很多业务处理。
工厂模式重构代码
设想的结构

1、首先定义公共方法的接口
1 2 3 4 5 6 7 8 9 10 11 12 13
   | package bestrookie.interfaces; import bestrookie.pojo.AwardReq;
 
 
 
  public interface ICommodity {     
 
 
      void send(AwardReq awardReq); }
   | 
 
2、定义各种奖励的实现类
优惠券:
1 2 3 4 5 6 7 8 9 10 11 12
   | package bestrookie.service; import bestrookie.interfaces.ICommodity; import bestrookie.pojo.AwardReq;
 
 
 
  public class CouponCommodityService implements ICommodity {     public void send(AwardReq awardReq) {         System.out.println("获得优惠券=====>"+awardReq.getUserName());     } }
   | 
 
实体商品:
1 2 3 4 5 6 7 8 9 10 11 12
   | package bestrookie.service; import bestrookie.interfaces.ICommodity; import bestrookie.pojo.AwardReq;
 
 
 
  public class GoodCommodityService implements ICommodity {     public void send(AwardReq awardReq) {         System.out.println("获得实物商品====》"+awardReq.getUserName());     } }
   | 
 
三方兑换卡:
1 2 3 4 5 6 7 8 9 10 11 12
   | package bestrookie.service; import bestrookie.interfaces.ICommodity; import bestrookie.pojo.AwardReq;
 
 
 
  public class CardCommodityService implements ICommodity {     public void send(AwardReq awardReq) {         System.out.println("三方兑换卡片=====》"+awardReq.getType());     } }
   | 
 
3、创建工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
   | package bestrookie.factory; import bestrookie.interfaces.ICommodity; import bestrookie.pojo.AwardReq; import bestrookie.service.CardCommodityService; import bestrookie.service.CouponCommodityService; import bestrookie.service.GoodCommodityService;
 
 
 
  public class StoreFactory {     public ICommodity getCommodityService(AwardReq awardReq) {         if (awardReq.getType() == 1){             return new CouponCommodityService();         }         if (awardReq.getType() == 2){             return new GoodCommodityService();         }         if (awardReq.getType() == 3){             return new CardCommodityService();         }         throw new RuntimeException("不存在服务类型");     }     public ICommodity getCommodityService(Class<?extends ICommodity> clazz) throws InstantiationException, IllegalAccessException {         if (clazz ==null){             return null;         }         return clazz.newInstance();     } }
   | 
 
4、实际调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | package bestrookie.controller; import bestrookie.factory.StoreFactory; import bestrookie.interfaces.ICommodity; import bestrookie.pojo.AwardReq;
 
 
 
  public class StoreFactoryController {     public static void main(String[] args) {         AwardReq awardReq = new AwardReq(1,"bestrookie",2);         StoreFactory storeFactory = new StoreFactory();         ICommodity commodityService = storeFactory.getCommodityService(awardReq);         commodityService.send(awardReq) ;     } }
   | 
 
- 从上面代码中可以看到,每一种奖品都包装到自己的类中,当新增、修改或删除逻辑时,都不会影响到其他奖品功能的测试,可以降低回归测试和响应的连带风险
 
- 如果有新增的奖品,只需要按照此结构进行填充对应的实现类即可。这样的实现方式非常易于维护和扩展
 
- 我们还可以统一入参以及出参,调用方不再关心奖品发放的内部逻辑,按照统一的方式即可处理
 
总结
从优化的过程来看,工厂模式并不复杂。一旦理解和掌握,会发现它更加简单,同时也可以借助它提升开发效率。同时,不难总结出它的有点:避免创建者与具体的产品逻辑耦合;满足单一职责,每一个业务逻辑实现都在自己所属的类中完成;满足开闭原则,无须更改使用调用方就可以在程序中引入新的产品类型。当然,这也将会带来一些问题,例如如有十分多的奖品类型,那么子类会急速扩张,因此需要使用其他的模式进行优化。