首页 > 其他分享 >四句话,让我掌握了工厂模式!

四句话,让我掌握了工厂模式!

时间:2022-09-28 12:06:13浏览次数:51  
标签:String 掌握 req 工厂 四句 new logger deliverReq uId

写在前面:

  初为职场新手,难免会把代码写的一把梭。遇到业务的时候直接if-else干。但是本着不想被开除的原则,还是学习一下设计模式,今天来看看设计模式之工厂模式。

四句话,让我掌握了工厂模式!_ico

用需求引出代码:

   抽奖系统当中有个业务是发奖业务,奖品有优惠券,实物商品,第三方优惠券。当用户抽中对应的奖品之后,我们需要有对应的方法来发奖。针对这样的业务我们先来看一下代码一把梭的情况。

工程结构:

四句话,让我掌握了工厂模式!_工厂模式_02

 

 

 

⼯程结构上⼀个⼊参对象 AwardReq 、⼀个出参对象 AwardRes ,以及⼀个接⼝类

PrizeController

 

先看看ifelse实现需求

public class PrizeController {

private Logger logger = LoggerFactory.getLogger(PrizeController.class);

/**
* 给用户发奖
* @param req
* @return
*/
public AwardRes awardToUser(AwardReq req) {
// 把req转为json格式好处理
String reqJson = JSON.toJSONString(req);
// 初始化返回结果为空
AwardRes awardRes = null;
try {
logger.info("奖品发放开始{}。req:{}", req.getuId(), reqJson);
// 按照不同类型方法商品[1优惠券、2实物商品、3第三方兑换卡(爱奇艺)]
if (req.getAwardType() == 1) {
// 这是1-00当中的类
CouponService couponService = new CouponService();
// 调用发放优惠券的方法
CouponResult couponResult = couponService.sendCoupon(req.getuId(), req.getAwardNumber(), req.getBizId());
if ("0000".equals(couponResult.getCode())) {
awardRes = new AwardRes("0000", "发放成功");
} else {
awardRes = new AwardRes("0001", couponResult.getInfo());
}
} else if (req.getAwardType() == 2) {
GoodsService goodsService = new GoodsService();
DeliverReq deliverReq = new DeliverReq();
// 初始化实物奖品的参数
deliverReq.setUserName(queryUserName(req.getuId()));
deliverReq.setUserPhone(queryUserPhoneNumber(req.getuId()));
deliverReq.setSku(req.getAwardNumber());
deliverReq.setOrderId(req.getBizId());
deliverReq.setConsigneeUserName(req.getExtMap().get("consigneeUserName"));
deliverReq.setConsigneeUserPhone(req.getExtMap().get("consigneeUserPhone"));
deliverReq.setConsigneeUserAddress(req.getExtMap().get("consigneeUserAddress"));
// 调用方法来发实物商品,如果发成功返回true
Boolean isSuccess = goodsService.deliverGoods(deliverReq);
if (isSuccess) {
awardRes = new AwardRes("0000", "发放成功");
} else {
awardRes = new AwardRes("0001", "发放失败");
}
} else if (req.getAwardType() == 3) {
String bindMobileNumber = queryUserPhoneNumber(req.getuId());
IQiYiCardService iQiYiCardService = new IQiYiCardService();
// 调用对应的方法来发第三方卡
iQiYiCardService.grantToken(bindMobileNumber, req.getAwardNumber());
awardRes = new AwardRes("0000", "发放成功");
}
logger.info("奖品发放完成{}。", req.getuId());
} catch (Exception e) {
logger.error("奖品发放失败{}。req:{}", req.getuId(), reqJson, e);
awardRes = new AwardRes("0001", e.getMessage());
}
return awardRes;
}

// 下面的两个都是测试数据,实际的话是从数据库当中去取出来的,并且还要做脱敏处理
private String queryUserName(String uId) {
return "花花";
}

private String queryUserPhoneNumber(String uId) {
return "15200101232";
}

}

如上的代码有什么问题?

  • 业务不变还好(基本不可能),业务如果变更,那就得去修改这个类中的代码,违背开闭原则(对修改关闭,对扩展开放),违背单一职责原则(一个类只干一件事)。
  • 被组长知道了,绩效3.0跑不了,假如离职下一个同事接手了估计直骂娘。

四句话,让我掌握了工厂模式!_工厂模式_03

 

 

接下来我们使用工厂模式重构代码,设计模式没什么可怕的,就是听起来高大上而已,要从战术上藐视他,多练练就学会了。

 

工程结构:

四句话,让我掌握了工厂模式!_工厂模式_04

为什么叫工厂模式呢?

  • 工厂是生产东西的,买家可以直接去工厂拿东西 ,并且工厂能生产的东西是多样性的。比如食品工厂,可以生产旺旺雪饼,雪糕,华夫饼。那我们需要去进货的时候,只需要带着需求清单去找工厂就行。

调用关系图:

四句话,让我掌握了工厂模式!_工厂模式_05

 

 具体代码实现:

发送商品接口:

public interface ICommodity {
void sendCommodity(String uId, String commodityId, String bizId,
Map<String, String> extMap) throws Exception;
}
  • 所有的奖品⽆论是实物、虚拟还是第三⽅,都需要通过我们的程序实现此接⼝进⾏处理,以保证最终⼊参出参的统⼀性。
  • 接⼝的⼊参包括:⽤户ID 、 奖品ID 、 业务ID 以及 扩展字段⽤于处理发放实物商品时的收获地址。

 

发优惠券:

public class CouponCommodityService implements ICommodity {

private Logger logger = LoggerFactory.getLogger(CouponCommodityService.class);

private CouponService couponService = new CouponService();

@Override
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
CouponResult couponResult = couponService.sendCoupon(uId, commodityId, bizId);
logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[优惠券]:{}", JSON.toJSON(couponResult));
if (!"0000".equals(couponResult.getCode())) throw new RuntimeException(couponResult.getInfo());
}

}

 

发实物商品

 

public class GoodsCommodityService implements ICommodity {

private Logger logger = LoggerFactory.getLogger(GoodsCommodityService.class);

private GoodsService goodsService = new GoodsService();

@Override
public 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);

logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[优惠券]:{}", isSuccess);

if (!isSuccess) throw new RuntimeException("实物商品发放失败");
}

private String queryUserName(String uId) {
return "花花";
}

private String queryUserPhoneNumber(String uId) {
return "15200101232";
}

}

发第三⽅兑换卡

public class CardCommodityService implements ICommodity {

private Logger logger = LoggerFactory.getLogger(CardCommodityService.class);

// 模拟注入
private IQiYiCardService iQiYiCardService = new IQiYiCardService();

@Override
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
String mobile = queryUserMobile(uId);
iQiYiCardService.grantToken(mobile, bizId);
logger.info("请求参数[爱奇艺兑换卡] => uId:{} commodityId:{} bizId:{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[爱奇艺兑换卡]:success");
}

private String queryUserMobile(String uId) {
return "15200101232";
}

}
  • 从上⾯可以看到每⼀种奖品的实现都包括在⾃⼰的类中,新增、修改或者删除都不会影响其他奖品功能的测试,降低回归测试的可能。后续在新增的奖品只需要按照此结构进⾏填充即可,⾮常易于维护和扩展。在统⼀了⼊参以及出参后,调⽤⽅不在需要关⼼奖品发放的内部逻辑,按照统⼀的⽅式即可处理。

 

最重要的工厂:

public class StoreFactory {

// 工厂对外交接部门,参数为接口类型。多态的体现
public ICommodity 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 配置结构,会让代码更加⼲净

总结:

  • 从上到下的优化来看,⼯⼚⽅法模式并不复杂,使用工厂模式之后代码结构更加清晰了,但是还是要根据业务和开发工期来动态决策具体该怎么写。
  • 最后我们用一个顺口溜来总结工厂模式,记住这几句顺口溜就是掌握了工厂模式。
  1. 工厂模式来发奖
  2. 优惠实物第三方
  3. 工厂当中传接口
  4. 接口之下有实现

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:String,掌握,req,工厂,四句,new,logger,deliverReq,uId
From: https://blog.51cto.com/u_15810109/5719132

相关文章

  • 工厂数字化转型离不开 MES 的原因是什么?
    工厂数字化转型是离不开MES,首先得弄清楚什么是工厂数字化转型、什么是MES,它们的关系是怎样的。数字化的主要含义是构建“业务数字化、数字资产化、资产服务化、服务业务......
  • 大话设计模式 ---- 第一章简单工厂笔记
    第一章简单工厂模式计算器实现建民哥在大二的时候让我们设计一个口算卡我第一版的设计模式:(虽然功能实现了,但是啥也不是,一旦有新要求需要大改程序直接作废)//......
  • 03-Go设计模式-工厂方法模式
    工厂模式方法模式示例代码/*工厂方法模式抽象工厂(AbstractFactory)角色:工厂方法模式的核心,任何工厂类都必须实现这个接口工厂(ConcreteFactory)角色:具体工厂类是抽象工......
  • 02-Go设计模式-简单工厂
    简单工厂模式示例代码/*简单工厂模式角色和职责工厂(Factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象......
  • 30分钟掌握 Webpack
    本文基于:峰华前端工程师--30分钟掌握Webpack为什么使用Webpack在我们进行传统网页开发中,会在index.html中引入大量的js和css文件,不仅可能会导致命名冲突,还会使......
  • 抽象工厂模式 Abstract Factory
    “对象创建”模式通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。典型模式......
  • 工厂方法模式 Factory Method
    “对象创建”模式通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。典型模式......
  • 设计模式 -- FactoryMethod(工厂方法)
    工厂方法(FactoryMethod)定义一个用于创建对象的接口,让子类决定实例化哪个类。FactoryMethod使得一个类的实例化延迟(目的:解耦)到子类。在软件系统中,经常会面临着创建对......
  • 彻底掌握Makeifle(三)
    彻底掌握Makeifle(三)前言在前面的文章彻底掌握Makefile(一)和彻底掌握Makefile(二)当中,我们简要的介绍了一些常见的makefile使用方法,在本篇文章当中我们将继续介绍一些makefil......
  • 跟我学Python图像处理丨带你掌握傅里叶变换原理及实现
    摘要:傅里叶变换主要是将时间域上的信号转变为频率域上的信号,用来进行图像除噪、图像增强等处理。本文分享自华为云社区《[Python图像处理]二十二.Python图像傅里叶变换原......