通往架构师之路系列之Java设计模式(二)工厂方法模式
前言
参考:虫洞栈
工厂模式又称工厂方法模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类
决定实例化对象的类型。
这种设计模式也是 Java 开发中最常见的一种模式,它的主要意图是定义一个创建对象的接口,让其子
类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
简单说就是为了提供代码结构的扩展性,屏蔽每一个功能类中的具体实现逻辑。让外部可以更加简单的
只是知道调用即可,同时,这也是去掉众多 ifelse 的方式。当然这可能也有一些缺点,比如需要实现
的类非常多,如何去维护,怎样减低开发成本。但这些问题都可以在后续的设计模式结合使用中,逐步
降低。
模拟发奖多种商品
现在我们有如下三种类型的商品接口:
序号 | 类型 | 接口 |
---|---|---|
1 | 优惠券 |
CouponResult sendCoupon(String uId, String couponNumber, String uuid) |
2 | 实物商品 | Boolean deliverGoods(DeliverReq req) |
3 | 第三方爱奇艺兑换卡 | void grantToken(String bindMobileNumber, String cardId) |
定义发奖接口
import java.util.Map;/*** 发奖接口** @author ZHANGCHAO* @version 1.0.0* @date 2022/1/28 14:50*/ public interface ICommodityService {void sendCommodity(String uId, String commodityId, String bizId,Map<String, String> extMap) throws Exception; }
所有的奖品无论是实物、虚拟还是第三方,都需要通过我们的程序实现此接口进行处理,以保证最终入参出参的统一性。
接口的入参包括:用户ID 、 奖品ID 、 业务ID 以及 扩展字段 用于处理发放实物商品时的收获址。实现奖品发放接口
2.1 优惠券package com.xiya.designpatterns.store.impl;import com.alibaba.fastjson.JSON; import com.xiya.designpatterns.coupon.CouponResult; import com.xiya.designpatterns.coupon.CouponService; import com.xiya.designpatterns.store.ICommodityService; import lombok.extern.slf4j.Slf4j;import java.util.Map;/*** 优惠券** @author ZHANGCHAO* @version 1.0.0* @date 2022/1/28 14:53*/ @Slf4j public class CouponCommodityService implements ICommodityService {private CouponService couponService = new CouponService();@Overridepublic void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {CouponResult couponResult = couponService.sendCoupon(uId, commodityId, bizId);log.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));log.info("测试结果[优惠券]:{}", JSON.toJSON(couponResult));if (!"0000".equals(couponResult.getCode())) throw new RuntimeException(couponResult.getInfo());} }
2.2 实物商品
package com.xiya.designpatterns.store.impl;import com.alibaba.fastjson.JSON; import com.xiya.designpatterns.goods.DeliverReq; import com.xiya.designpatterns.goods.GoodsService; import com.xiya.designpatterns.store.ICommodityService; import lombok.extern.slf4j.Slf4j;import java.util.Map;/*** 实物奖励** @author ZHANGCHAO* @version 1.0.0* @date 2022/1/28 15:14*/ @Slf4j public class GoodsCommodityService implements ICommodityService {private GoodsService goodsService = new GoodsService();@Overridepublic void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {DeliverReq deliverReq = new DeliverReq();deliverReq.setUserName(queryUserName(uId));deliverReq.setUserPhone(queryUserPhoneNumber(uId));deliverReq.setSku(commodityId);deliverReq.setOrderId(bizId);deliverReq.setConsigneeUserName(extMap.get("consigneeUserName"));deliverReq.setConsigneeUserPhone(extMap.get("consigneeUserPhone"));deliverReq.setConsigneeUserAddress(extMap.get("consigneeUserAddress"));Boolean isSuccess = goodsService.deliverGoods(deliverReq);log.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));log.info("测试结果[优惠券]:{}", isSuccess);if (!isSuccess) throw new RuntimeException("实物商品发放失败");}private String queryUserName(String uId) {return "花花";}private String queryUserPhoneNumber(String uId) {return "15200101232";} }
2.3 第三⽅兑换卡
package com.xiya.designpatterns.store.impl;import com.alibaba.fastjson.JSON; import com.xiya.designpatterns.card.IQiYiCardService; import com.xiya.designpatterns.store.ICommodityService; import lombok.extern.slf4j.Slf4j;import java.util.Map;/*** 第三方兑换卡** @author ZHANGCHAO* @version 1.0.0* @date 2022/1/28 15:22*/ @Slf4j public class CardCommodityService implements ICommodityService {// 模拟注⼊private IQiYiCardService iQiYiCardService = new IQiYiCardService();@Overridepublic void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {String mobile = queryUserMobile(uId);iQiYiCardService.grantToken(mobile, bizId);log.info("请求参数[爱奇艺兑换卡] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));log.info("测试结果[爱奇艺兑换卡]:success");}private String queryUserMobile(String uId) {return "15200101232";} }
从上面可以看到每一种奖品的实现都包括在自己的类中,新增、修改或者删除都不会影响其他奖品功能的测试,降低回归测试的可能。
后续在新增的奖品只需要按照此结构进⾏填充即可,⾮常易于维护和扩展。
在统一了入参以及出参后,调用方不在需要关心奖品发放的内部逻辑,按照统一的方式即可处理。创建商店⼯⼚
package com.xiya.designpatterns.store;import com.xiya.designpatterns.store.impl.CardCommodityService; import com.xiya.designpatterns.store.impl.CouponCommodityService; import com.xiya.designpatterns.store.impl.GoodsCommodityService; import lombok.extern.slf4j.Slf4j;/*** 商店⼯⼚** @author ZHANGCHAO* @version 1.0.0* @date 2022/1/28 16:00*/ @Slf4j public class StoreFactory {public ICommodityService getCommodityService(Integer commodityType) {if (null == commodityType) return null;if (1 == commodityType) return new CouponCommodityService();if (2 == commodityType) return new GoodsCommodityService();if (3 == commodityType) return new CardCommodityService();throw new RuntimeException("不存在的商品服务类型");} }
这里我们定义了一个商店的工厂类,在里面按照类型实现各种商品的服务。可以非常干净整洁的处
理你的代码,后续新增的商品在这里扩展即可。如果你不喜欢 if 判断,也可以使用 switch 或
者 map 配置结构,会让代码更加干净。测试验证
package com.xiya.designpatterns.store;import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test;import java.util.HashMap; import java.util.Map;/*** @author ZHANGCHAO* @version 1.0.0* @date 2022/1/28 16:04*/ @Slf4j class StoreFactoryTest {@Testvoid test_factory() throws Exception {StoreFactory storeFactory = new StoreFactory();// 1.优惠券ICommodityService commodityService1 = storeFactory.getCommodityService(1);commodityService1.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null);// 2.实物商品ICommodityService commodityService2 = storeFactory.getCommodityService(2);Map<String, String> extMap = new HashMap<>();extMap.put("consigneeUserName", "谢飞机");extMap.put("consigneeUserPhone", "15200292123");extMap.put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109");commodityService2.sendCommodity("10001", "9820198721311", "1023000020112221113", new HashMap<>() {{put("consigneeUserName", "谢飞机");put("consigneeUserPhone", "15200292123");put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109");}});// 3.第三方兑换卡(爱奇艺)ICommodityService commodityService3 = storeFactory.getCommodityService(3);commodityService3.sendCommodity("10001", "AQY1xjkUodl8LO975GdfrYUio", null, null);}}
运行结果正常,既满⾜了业务产品需求,也满足了自己对代码的追求。这样的代码部署上线运行,内心不会恐慌,不会觉得半夜会有电话。
附项目结构图:
总结
- 从上到下的优化来看,工厂方法模式并不复杂,甚至这样的开发结构在你有所理解后,会发现更加简单了。
- 那么这样的开发的好处知道后,也可以总结出来它的优点; 避免创建者与具体的产品逻辑耦合 、 满足单一职责,每一个业务逻辑实现都在所属自己的类中完成 、 满足开闭原则,无需更改使用调用方就可以在程序中引入新的产品类型 。但这样也会带来一些问题,比如有非常多的奖品类型,那么实现的子类会极速扩张。因此也需要使用其他的模式进行优化,这些在后续的设计模式中会逐步涉及到。
- 从案例入手看设计模式往往要比看理论学的更加容易,因为案例是缩短理论到上手的最佳方式,如果你已经有所收获,一定要去尝试实操。
通往架构师之路系列之Java设计模式(二)工厂方法模式相关推荐
- 一文叫你弄懂Java设计模式之工厂方法模式:图解+日志记录器代码实例
文章目录 详解Java设计模式之工厂方法模式 案例引入工厂方法模式 工厂方法模式 定义 案例分析 UML类图分析 代码分析 工厂方法的重载 工厂方法的隐藏 模式优点 模式缺点 模式适用环境 详解Jav ...
- JAVA架构师之路十六:设计模式之责任链模式
JAVA架构师之路十五:设计模式之策略模式 责任链模式 1. 责任链模式 2. 登陆案例 3. 登陆案例优化 人生的游戏不在于拿了一副好牌,而在于怎样去打好坏牌,世上没有常胜将军,勇于超越自我者才能得 ...
- Java设计模式之工厂方法模式与抽象工厂模式
2019独角兽企业重金招聘Python工程师标准>>> 一.前期回顾 上一篇<Java设计模式之单例模式>详细介绍了单例模式,介绍了单例模式的使用场景,优缺点,同时也写了 ...
- Java 设计模式之工厂方法模式
本文为笔者学习<Head First设计模式>的笔记,并加入笔者自己的理解和归纳总结 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类 ...
- 最简单java设计模式:工厂方法模式
前言 在前一篇文章讲解了一下简单工厂模式,在上篇文章中,我们也讲到了简单工厂模式的缺点,就是不满足开闭原则,这对于软件的设计来说,是不太好的,而下面讲解的工厂方法模式,正是为了弥补简单工厂模式的缺点, ...
- Java设计模式 之 工厂方法模式
1. 使用设计模式的好处:可提高代码的重复性,让代码更容易被他人理解,保证代码的可靠性. 2. 工厂模式定义:就是创建一个工厂类来创建你需要的类,工厂模式包括工厂模式和抽象工厂模式,抽象工厂模式是工厂 ...
- java设计模式通俗_通俗易懂的Java设计模式之工厂方法模式
一 .工厂方法(Factory Method)模式 工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中.核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负 ...
- java设计模式之工厂方法模式
工厂方法模式是类的创建模式,又叫虚拟构造模式(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式. 工厂方法模式的用意是定义一个创建产品的工厂接口, ...
- java设计模式1——工厂方法模式(Factory Method)
工厂方法模式分为三种: 1.普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建.首先看下关系图: 举例如下:(我们举一个发送邮件和短信的例子) 首先,创建二者的共同接口: pub ...
最新文章
- 《1---关于解决MySQL在控制台插入中文乱码问题》
- AngularUI Router
- 如何在代码中将menu隐藏_如何在40行代码中将机器学习用于光学/光子学应用
- 告别自注意力,谷歌为Transformer打造新内核Synthesizer
- Ansys节点数据批量一键导出脚本生成CSV (ansys数据导出利用matlab脚本)
- 如何“神还原”数据中心? 阿里联合NTU打造了工业级精度的仿真沙盘!
- [转载]JavaScript 的轻框架开发
- Dropout也能自动化了,谷歌Quoc Le等人利用强化学习自动找寻模型专用Dropout
- 响应信息有json和html,获取HTML响应而不是Json响应
- Android 系统调试(2)---android debug 方法
- Windows mobile 下读取手机SIM卡信息
- OWASP Hakcing Lab在线漏洞环境
- python tqdm模块的简单使用
- 公有云安全修炼之路,郭靖和周伯通带你走
- 阿里easyexcel读取excel流程初探
- 一键查询自己名下所有微信账户
- 创业教父马云的经典语录
- Microchip最新推出的ATMEGA4809-XPRO开发板简介
- 荣耀3路由器设置虚拟服务器,荣耀路由3怎么设置上网?(电脑)
- js中appendChild的用法