设计模式-工厂方法模式
一、工厂方法模式介绍
工厂模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
工厂模式是 Java 开发中最常见的一种模式,其主要意图是定义一个创建对象的接口,让其子类决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
简单说就是为了提供代码的可扩展性,屏蔽每一个功能类中的具体实现逻辑。让外部可以更加简单的调用。同时,可以去掉众多 ifelse
。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
二、模拟多种奖品发放
营销场景中经常会有抽奖活动,我们在这里模拟兑换多种类型的商品。
假如我们有如下三种类型的商品接口:
序号 | 类型 | 接口 |
---|---|---|
1 | 代金劵 | VoucherResult sendVoucher(String userId, String voucherId, int voucherNumber) |
2 | VIP体验卡 | void openVIP(String userId, Date date, String time) |
3 | 实物奖品 | Boolean deliverGoods(DeliverRequest req) |
- 三个接口返回类型不同,有对象类型、布尔类型、void
- 入参不同,代金券需要代金券 id 和代金券数量、VIP体验卡需要体验时间、实物奖品需要奖品对象(包含发货地址等)
- 可能随着业务的拓展,会增加其他商品类型。
三、非工厂模式实现
1. ifelse实现需求
public class PrizeController { private static final String CODE_SUCCESS = "11111111"; private static final String CODE_FAIL = "00000000"; public AwardResult awardToUser(AwardRequest req) { AwardResult res = null; // 按照不同类型分法商品[1代金劵、2VIP体验卡、3实物奖品] if (req.getAwardType() == 1) { VoucherService voucherService = new VoucherService(); VoucherResult voucherResult = voucherService.sendVoucher(req.getUserId(), req.getAwardId(), req.getAwardNumber()); if (CODE_SUCCESS.equals(voucherResult.getCode())) { res = new AwardResult(CODE_SUCCESS, "成功"); } else { res = new AwardResult(CODE_FAIL, voucherResult.getInfo()); } } else if (req.getAwardType() == 2) { VIPService vipService = new VIPService(); Date date = new Date(System.currentTimeMillis()); vipService.openVip(req.getUserId(), date, req.getTime()); res = new AwardResult(CODE_SUCCESS, "成功"); } else if (req.getAwardType() == 3) { GoodsService goodsService = new GoodsService(); DeliverRequest deliverRequest = new DeliverRequest(); deliverRequest.setUserId(req.getUserId()); deliverRequest.setUserName(queryUserNameById(req.getUserId())); deliverRequest.setUserPhone(queryUserPhoneById(req.getUserId())); deliverRequest.setUserAddress(queryUserAddressById(req.getUserId())); Boolean isSuccess = goodsService.deliverGoods(deliverRequest); if (isSuccess) { res = new AwardResult(CODE_SUCCESS, "成功"); } else { res = new AwardResult(CODE_FAIL, "失败"); } } return res; } public String queryUserNameById(String userId) { return "Tom"; } public String queryUserPhoneById(String userId) { return "123456789"; } public String queryUserAddressById(String userId) { return "BeiJin"; }}
- 如上为使用
ifelse
实现业务需求。如果仅从业务角度看,已经实现了基本功能。 - 但是经过几次迭代后,接手这段代码的研发将十分痛苦。重构成本高,且需要理清之前的每一个接口的使用,测试回归验证时间长,需要全部验证一次。
2. 测试验证
@Testpublic void testAwardToUser() { PrizeController prizeController = new PrizeController(); AwardResult awardResult = null; System.out.println("******模拟多种奖品发放测试******"); AwardRequest awardReq = new AwardRequest(); awardReq.setAwardId("0001"); awardReq.setAwardNumber(1); awardReq.setUserId("10001"); System.out.println("\n------ 代金券的发放 ------"); awardReq.setAwardType(1); awardResult = prizeController.awardToUser(awardReq); System.out.println("代金券发放结果:" + awardResult.getRes()); System.out.println("\n------ VIP体验卡的发放 -------"); awardReq.setAwardType(2); awardResult = prizeController.awardToUser(awardReq); System.out.println("VIP体验卡发放结果:" + awardResult.getRes()); System.out.println("\n------ 实物奖品的发放 -------"); awardReq.setAwardType(3); awardResult = prizeController.awardToUser(awardReq); System.out.println("实物奖品发放结果:" + awardResult.getRes());}
结果:
- 运行结果正常,满足业务需求。写的还很快,但是实在难以维护。
四、工厂模式优化代码
1. 代码实现
1.1 定义发奖接口
public interface IAward { void sendAward(String userId, String awardId, Map<String, Object> map);}
1.2 实现发奖接口
代金券
public class VoucherAwardService implements IAward{ private VoucherService voucherService = new VoucherService(); @Override public void sendAward(String userId, String awardId, Map<String, Object> map) throws Exception{ VoucherResult voucherResult = voucherService.sendVoucher(userId, awardId, (int) map.get("voucherNumber")); if (PrizeController.CODE_FAIL.equals(voucherResult.getCode())) { throw new RuntimeException("失败"); } }}
VIP体验卡
public class VIPAwardService implements IAward{ private VIPService vipService = new VIPService(); @Override public void sendAward(String userId, String awardId, Map<String, Object> map) throws Exception { Date date = new Date(System.currentTimeMillis()); vipService.openVip(userId, (Date) map.get("data"), (String) map.get("time")); }}
实物奖品
public class GoodsAwardService implements IAward{ private GoodsService goodsService = new GoodsService(); @Override public void sendAward(String userId, String awardId, Map<String, Object> map) throws Exception { DeliverRequest deliverRequest = new DeliverRequest(); deliverRequest.setUserId(userId); deliverRequest.setUserName(queryUserNameById(userId)); deliverRequest.setUserPhone(queryUserPhoneById(userId)); deliverRequest.setUserAddress(queryUserAddressById(userId)); Boolean isSuccess = goodsService.deliverGoods(deliverRequest); if (!isSuccess) { throw new RuntimeException("失败"); } } public String queryUserNameById(String userId) { return "Tom"; } public String queryUserPhoneById(String userId) { return "123456789"; } public String queryUserAddressById(String userId) { return "BeiJin"; }}
- 可以看到每一种奖品的实现都包括在自己的类中,新增、修改或者删除都不会影响其他奖品功能的测试
- 后续再新增的奖品只需要按照此结构进行填充即可,非常易于维护和扩展
- 统一入参和出参后,调用方不在需要关心内部的实现逻辑,按照统一方式处理即可
1.3 创建奖品工厂
public class AwardFactory { public IAward getAwardService(Integer awardType) throws Exception{ if (awardType == null) return null; if (1 == awardType) return new VoucherAwardService(); if (2 == awardType) return new VIPAwardService(); if (3 == awardType) return new GoodsAwardService(); throw new RuntimeException("不存在此奖品类型"); }}
2.测试验证
@Testpublic void testIAward() throws Exception{ AwardFactory awardFactory = new AwardFactory(); System.out.println("******模拟多种奖品发放测试******"); System.out.println("\n------ 代金券的发放 ------"); IAward awardService1 = awardFactory.getAwardService(1); Map<String, Object> map1 = new HashMap<>(); map1.put("voucherNumber", 1); awardService1.sendAward("10001", "123456712", map1); System.out.println("\n------ VIP体验卡的发放 -------"); IAward awardService2 = awardFactory.getAwardService(2); Map<String, Object> map2 = new HashMap<>(); map2.put("data", new Date(System.currentTimeMillis())); map2.put("time", "23:59:59"); awardService2.sendAward("10002", "123123414", map2); System.out.println("\n------ 实物奖品的发放 -------"); IAward awardService3 = awardFactory.getAwardService(3); awardService3.sendAward("10003", "12312451", null);}
五、总结
工厂模式可以避免创建者与具体的产品逻辑耦合、满足单一职责,每一个业务逻辑实现都在所属自己的类中完成、满足开闭原则,无需修改调用方就可以在程序中引入新的产品类型。
但这样也会带来一些问题,比如有非常多的奖品类型,那么实现的子类会急速扩张。
原文转载:http://www.shaoqun.com/a/583583.html
刘军:https://www.ikjzd.com/w/1835
万国邮政联盟:https://www.ikjzd.com/w/861
设计模式-工厂方法模式一、工厂方法模式介绍工厂模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。工厂模式是Java开发中最常见的一种模式,其主要意图是定义一个创建对象的接口,让其子类决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。简单说就是为了提供代码的可扩展性,屏蔽每一个功能类中的具体实现逻辑。让外部可以更加简单的调用。同时,可以去掉众多if
派代:https://www.ikjzd.com/w/2197
reddit:https://www.ikjzd.com/w/180
agora:https://www.ikjzd.com/w/2176
亚马逊在测试好评删除系统?review直接被撸空!:https://www.ikjzd.com/home/111392
惨!新年大礼包,姐夫"索命邮件"来袭!:https://www.ikjzd.com/home/113736
2019网购消费者购物方式发生了这3大变化!:https://www.ikjzd.com/home/20950
没有评论:
发表评论