阅读《重学设计模式》笔记1 - 工厂模式

2023-07-11  本文已影响0人  欢喜的看着书

1、设计模式遵循六大原则:

2、设计模式可以笼统的分为三大类

2.1 创建者模式

这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤用性。

创建者模式

2.2 结构型模式

这类模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。


2.3 ⾏为模式

这类模式负责对象间的高效沟通和职责委派。


行为模式

3 工厂方法模式

⼯厂方法模式

⼯⼚模式⼜称⼯⼚⽅法模式,是⼀种创建型设计模式,其在⽗类中提供⼀个创建对象的⽅法, 允许⼦类
决定实例化对象的类型。
这种设计模式也是 Java 开发中最常⻅的⼀种模式,它的主要意图是定义⼀个创建对象的接⼝,让其⼦类⾃⼰决定实例化哪⼀个⼯⼚类,⼯⼚模式使其创建过程延迟到⼦类进⾏。
简单说就是为了提供代码结构的扩展性,屏蔽每⼀个功能类中的具体实现逻辑。让外部可以更加简单的只是知道调⽤即可,同时,这也是去掉众多 ifelse 的⽅式。当然这可能也有⼀些缺点,⽐如需要实现的类⾮常多,如何去维护,怎样减低开发成本。但这些问题都可以在后续的设计模式结合使⽤中,逐步降低。

3.2、案例 - 模拟发奖多种商品

为了可以让整个学习的案例更加贴近实际开发,这⾥模拟互联⽹中在营销场景下的业务。由于营销场景
的复杂、多变、临时的特性,它所需要的设计需要更加深⼊,否则会经常⾯临各种紧急CRUD操作,从
⽽让代码结构混乱不堪,难以维护。
在营销场景中经常会有某个⽤户做了⼀些操作;打卡、分享、留⾔、邀请注册等等,进⾏返利积分,最
后通过积分在兑换商品,从⽽促活和拉新。
那么在这⾥我们模拟积分兑换中的发放多种类型商品,假如现在我们有如下三种类型的商品接⼝;


从以上接⼝来看有如下信息:

3.2.2 ⽤⼀坨坨代码实现

如果不考虑任何扩展性,只为了尽快满⾜需求,那么对这么⼏种奖励发放只需使⽤ifelse语句判断,调⽤不同的接⼝即可满⾜需求。可能这也是⼀些刚⼊⻔编程的⼩伙伴,常⽤的⽅式。接下来我们就先按照这样的⽅式来实现业务的需求。
1、工厂结构


  1. ifelse实现需求
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";
    }

}

3.3、工厂模式优化代码

接下来使用工厂方法模式来进行代码优化,也算是一次很小的重构。整理重构会你会发现代码结构清晰了、也具备了下次新增业务需求的扩展性。但在实际使用中还会对此进行完善,目前的只是抽离出最核心的部分。

1. 工程结构

itstack-demo-design-1-02
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.design
    │           ├── store    
    │           │   ├── impl
    │           │   │   ├── CardCommodityService.java
    │           │   │   ├── CouponCommodityService.java 
    │           │   │   └── GoodsCommodityService.java  
    │           │   └── ICommodity.java
    │           └── StoreFactory.java 
    └── test
         └── java
             └── org.itstack.demo.design.test
                 └── ApiTest.java

2. 代码实现

2.1 定义发奖接口

public interface ICommodity {

    void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception;

}

2.2 实现奖品发放接口

优惠券

public class CouponCommodityService implements ICommodity {

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

    private CouponService couponService = new CouponService();

    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();

    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();

    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";
    }

}

2.3 创建商店工厂

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("不存在的商品服务类型");
    }

}

4、总结

上一篇 下一篇

猜你喜欢

热点阅读