工厂模式介绍
工厂模式也称简单工厂模式,是创建型设计模式的一种,这种设计模式提供了按需创建对象的最佳方式。同时,这种创建方式不会对外暴露创建西街,并且会通一个统一的接口创建所需对象。
这种设计模式也是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) ; } }
|
- 从上面代码中可以看到,每一种奖品都包装到自己的类中,当新增、修改或删除逻辑时,都不会影响到其他奖品功能的测试,可以降低回归测试和响应的连带风险
- 如果有新增的奖品,只需要按照此结构进行填充对应的实现类即可。这样的实现方式非常易于维护和扩展
- 我们还可以统一入参以及出参,调用方不再关心奖品发放的内部逻辑,按照统一的方式即可处理
总结
从优化的过程来看,工厂模式并不复杂。一旦理解和掌握,会发现它更加简单,同时也可以借助它提升开发效率。同时,不难总结出它的有点:避免创建者与具体的产品逻辑耦合;满足单一职责,每一个业务逻辑实现都在自己所属的类中完成;满足开闭原则,无须更改使用调用方就可以在程序中引入新的产品类型。当然,这也将会带来一些问题,例如如有十分多的奖品类型,那么子类会急速扩张,因此需要使用其他的模式进行优化。