首页 > 其他分享 >工厂模式

工厂模式

时间:2022-08-13 20:33:23浏览次数:47  
标签:uId req 模式 工厂 new logger deliverReq String

写在前面:

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

用需求引出代码:

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

工程结构:

 

 

 

⼯程结构上⼀个⼊参对象 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跑不了,假如离职下一个同事接手了估计直骂娘。

 

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

为什么叫工厂模式呢?

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

调用关系图:

 

 具体代码实现:

发送商品接口:

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 配置结构,会让代码更加⼲净
总结:
  • 从上到下的优化来看,⼯⼚⽅法模式并不复杂,使用工厂模式之后代码结构更加清晰了,但是还是要根据业务和开发工期来动态决策具体该怎么写。
                       

 

标签:uId,req,模式,工厂,new,logger,deliverReq,String
From: https://www.cnblogs.com/YXBLOGXYY/p/16583956.html

相关文章