设计模式之工厂模式08

目录

1.概述

2.业务场景

3.运用设计模式前代码实现

3.1.代码实现

3.2.总结

4.运用设计模式后代码实现

4.1.代码实现

4.2.总结


1.概述

工厂模式也称简单工厂模式,是创建型设计模式的一种,这种设计模式提供了按需创建对象的最佳方式。同时,这种创建方式不会对外暴露创建细节,并且会通过一个统一的接口创建所需对象。这种设计模式也是Java开发中常见的一种模式,它的主要意图是定义一个创建对象的接口,让其子类自己决定将哪一个工厂类实例化,工厂模式使创建过程延迟到子类中进行。

简单地说,就是为了给代码结构提供扩展性,屏蔽每一个功能类中的具体实现逻辑。这种方式便于外部更加简单地调用,同时也是去掉众多if…else的最佳手段。当然,这种设计模式也有一些缺点,需要治理。例如需要实现的类比较多、难以维护、开发成本高等,但这些问题都可以通过结合不同的设计模式逐步优化。

2.业务场景

在营销场景中,经常会约定在用户完成打卡、分享、留言、邀请注册等一系列行为操作后进行返利积分操作。用户再通过这些返利积分兑换商品,从而让整个系统构成一个生态闭环,达到促活和拉新的目的。此处有优惠券,实物商品和第三方兑换卡三种营销方式。

3.运用设计模式前代码实现

3.1.代码实现

PrizeController.java

package chapter04;
​
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
public class PrizeController {
    private Logger logger = LoggerFactory.getLogger(PrizeController.class);
​
    public AwardRes awardToUser(AwardReq req){
        String reqJson = JSON.toJSONString(req);
        AwardRes awardRes =  null;
        try{
            logger.info("奖品发放开始{},req:{}",req.getuId(),reqJson);
            //按照不同类型发放商品[1 优惠券,2 实物商品,3 第三方兑换卡(爱奇艺)]
            if(req.getAwardType() == 1){
                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"));
                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";
    }
}

测试用例

@Test
public void test_awardToUser(){
    PrizeController prizeController = new PrizeController();
    System.out.println("\r\n模拟发放优惠券测试\r\n");
    //模拟发放优惠券测试
    AwardReq req01 = new AwardReq();
    req01.setuId("1001");
    req01.setAwardType(1);
    req01.setAwardNumber("EGM102393891292992");
    req01.setBizId("7910987");
    AwardRes awardRes01 = prizeController.awardToUser(req01);
    logger.info("请求参数:{}", JSON.toJSON(req01));
    logger.info("测试结果:{}",JSON.toJSON(awardRes01));
    System.out.println("\r\n模拟发放实物商品\r\n");
​
    //模拟发放实物商品
    AwardReq req02 = new AwardReq();
    req02.setuId("1001");
    req02.setAwardType(2);
    req02.setAwardNumber("98201989");
    req02.setBizId("102300002011");
    Map<String,String> extMap = new HashMap<String,String>();
    extMap.put("consigneeUserName","谢先生");
    extMap.put("consigneeUserPhone","15200291234");
    extMap.put("consigneeUserAddress","吉林省,长春市,xxx");
    req02.setExtMap(extMap);
    AwardRes awardRes02 = prizeController.awardToUser(req02);
    logger.info("请求参数:{}", JSON.toJSON(req02));
    logger.info("测试结果:{}",JSON.toJSON(awardRes02));
    System.out.println("\r\n第三方兑换卡\r\n");
    AwardReq req03 = new AwardReq();
    req03.setuId("1001");
    req03.setAwardType(3);
    req03.setAwardNumber("98201989");
    AwardRes awardRes03 = prizeController.awardToUser(req03);
    logger.info("请求参数:{}", JSON.toJSON(req03));
    logger.info("测试结果:{}",JSON.toJSON(awardRes03));
}

3.2.总结

上述代码使用了if…else语句,用非常直接的方式实现了业务需求。如果仅从产品需求角度来说,确实实现了相应的功能逻辑。甚至靠这样简单粗暴的开发方式,也许能让需求提前上线。既然这样的代码可以实现快速交付,又存在什么问题呢?在互联网业务快速迭代的情况下,这段代码会在源源不断的需求中迭代和拓展。如果这些逻辑都用 if…else填充到一个类里,则非常难以维护。这样的代码使用的时间越久,其重构成本就越高。重构前需要清理所有的使用方,测试回归验证时间加长,带来的风险也会非常高。所以,很多研发人员并不愿意接手这样的代码,如果接手后需求开发又非常紧急,可能根本来不及重构,导致这样的if…else语句还会继续增加。

4.运用设计模式后代码实现

接下来使用工厂模式优化代码,也算是一次代码重构。当整理代码流程并重构后,会发现代码结构更清晰了,也具备了应对下次新增业务需求的扩展性。

4.1.代码实现

ICommodity.java

package chapter04.design.store;
​
import java.util.Map;
​
public interface ICommodity {
    void sendCommodity(String uId, String commodityId, String bizId, Map<String,String> extMap);
}

CardCommodityService.java

package chapter04.design.store.impl;
​
import chapter04.AwardRes;
import chapter04.IQiYiCardService;
import chapter04.design.store.ICommodity;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import java.util.Map;
​
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) {
        String bindMobileNumber = queryUserPhoneNumber(uId);
​
        iQiYiCardService.grantToken(bindMobileNumber,bizId);
        logger.info("请求参数[兑换卡]=> uId:{} commodityId:{} bizId:{} extMap:{}",uId,commodityId,bizId, JSON.toJSON(extMap));
        logger.info("测试结果[兑换卡]:success");
    }
​
    private String queryUserPhoneNumber(String uId){
        return "15200101232";
    }
}

CouponCommodityService.java

package chapter04.design.store.impl;
​
import chapter04.CouponResult;
import chapter04.CouponService;
import chapter04.design.store.ICommodity;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import java.util.Map;
​
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) {
        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());
        }
    }
}

GoodsCommodityService.java

package chapter04.design.store.impl;
​
import chapter04.AwardRes;
import chapter04.DeliverReq;
import chapter04.GoodsService;
import chapter04.design.store.ICommodity;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import java.util.Map;
​
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) {
​
        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";
    }
}

StoreFactory.java

package chapter04.design.store;
​
import chapter04.design.store.impl.CardCommodityService;
import chapter04.design.store.impl.CouponCommodityService;
import chapter04.design.store.impl.GoodsCommodityService;
​
public class StoreFactory {
    /**
     * 奖品类型方式实例化
     *
     * @param commodityType 奖品类型
     * @return 实例化对象
     */
    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("不存在的奖品服务类型");
    }
​
    /**
     * 奖品类信息方式实例化
     *
     * @param clazz 奖品类型
     * @return 实例化对象
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public ICommodity getCommodityService(Class<? extends ICommodity> clazz) throws InstantiationException, IllegalAccessException {
        if (null == clazz) return null;
        return clazz.newInstance();
    }
}

测试用例

@Test
public void test_StoreFactory_01(){
    StoreFactory storeFactory = new StoreFactory();
    //1.优惠券
    ICommodity commodityService_1 = storeFactory.getCommodityService(1);
    commodityService_1.sendCommodity("1001","EGM10239389","79109864",null);
​
    //2.实物商品
    ICommodity commodityService_2 = storeFactory.getCommodityService(2);
    commodityService_2.sendCommodity("1001","98201989","1023002011",new HashMap<String, String>(){{
        put("consigneeUserName","谢先生");
        put("consigneeUserPhone","152002929202");
        put("consigneeUserAddrss","吉林省长春市xxxx");
    }});
​
    //3.第三方兑换卡
    ICommodity commodityService_3 = storeFactory.getCommodityService(3);
    commodityService_3.sendCommodity("1001","11343433",null,null);
}
​
@Test
public void test_ScoreFactory_02() throws Exception{
    StoreFactory storeFactory = new StoreFactory();
    //1.优惠券
    ICommodity commodityService = storeFactory.getCommodityService(CouponCommodityService.class);
    commodityService.sendCommodity("1001","EGM10239389","79109864",null);
​
}

4.2.总结

从运行结果可以看到,这两种获取工厂实现的接口都可以满足业务需求。在实际使用中按需选择即可。这段重构后的代码既满足了业务方和产品经理的需求,也满足了研发人员对代码质量的追求。另外,从运行的测试结果也可以看出来,在进行封装后,这样一整套发放奖品服务有统一的入参、统一的结果。既提高了代码的结构性,也让工程易于维护和扩展。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值