• 工厂方法模式


    工厂方法模式是一种创建型设计模式,在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

    意图

    定义一个创建对象的接口,让其子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类执行。屏蔽每一个功能类中的具体实现逻辑,让外部可以更加简单的只是知道调用即可

    案例

    模拟积分兑换中的发放多种类型商品,有三种商品类型:

    商品类型接口
    实物商品Boolean deliverGoods(deliverReq req);
    优惠券CouponResult sendCoupon(String uId,String couponNumber,String uuid);
    爱奇艺会员兑换卡void grantToken(String bindMobileNumber,String cardId);
    • 三个接口返回类型不同
    • 入参不同,因为每种商品需要的东西不同
    • 可能后续会新增其他的商品类型

    实现

    普通实现(源代码)

    public AwardResp awardToUser(AwardReq req) {
    
            String reqJson = JSONObject.toJSONString(req);
    
            log.info("奖品发放开始{}. req:{}", req.getUId(), reqJson);
            AwardResp resp = null;
            try {
                //按照不同类型方法商品[1.优惠券 2.实物商品 3.爱奇艺会员兑换卡]
                if (req.getAwardType() == 1) {
                    CouponService couponService = new CouponService();
                    CouponResult couponResult = couponService.sendCoupon(req.getUId(), req.getAwardNumber(), req.getBizId());
                    if ("200".equals(couponResult.getCode())) {
                        resp = new AwardResp("200", "发放成功");
                    } else {
                        resp = new AwardResp("500", couponResult.getMessage());
                    }
                } 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.setConsigneeUserAddress(req.getExtMap().get("consigneeUserAddress"));
                    deliverReq.setConsigneeUserPhone(req.getExtMap().get("consigneeUserPhone"));
                    Boolean sendResult = goodsService.deliverGoods(deliverReq);
                    if (sendResult) {
                        resp = new AwardResp("200", "发放成功");
                    } else {
                        resp = new AwardResp("500", "发放失败");
                    }
                } else if (req.getAwardType() == 3) {
                    IQiYiCardService iQiYiCardService = new IQiYiCardService();
                    iQiYiCardService.grantToken(queryUserPhoneNumber(req.getUId()), req.getAwardNumber());
                    resp = new AwardResp("200", "发放成功");
                }
                log.info("奖品发放完成:" + req.getUId());
            } catch (Exception e) {
                log.info("奖品发放异常 ,用户{},req:{}", req.getUId(), reqJson, e);
                resp = new AwardResp("500", e.getMessage());
            }
            return resp;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    设计模式实现

    /**
     * Description:发奖接口,无论是什么商品类型都需要实现这个接口,统一出入参
     */
    public interface ICommodity {
    
        /**
         * @param uId 用户ID
         * @param commodityId 商品ID
         * @param bizId 业务ID
         * @param extParam 扩展字段
         */
        void sendCommodity(String uId, String commodityId, String bizId, Map extParam) throws Exception;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    /**
     * Description:商店工厂
     *
     * @author li.hongjian
     * @email lhj502819@163.com
     * @since 2022/9/4 11:47
     */
    public class StoreFactory {
    
        public ICommodity getCommodityService(Integer commodityType) {
            if (null == commodityType) {
                return null;
            }
            switch (commodityType) {
                case 1:
                    return new CouponCommodityService();
                case 2:
                    return new GoodsCommodityService();
                case 3:
                    return new IQiYiCommodityService();
            }
            throw new RuntimeException("该商品类型不支持");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUMguyRB-1662287577336)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220904183247973.png)]

    优点

    • 避免创建者与具体产品逻辑耦合、满足单一职责,每一个业务逻辑实现都再所属自己的类中完成、满足开闭原则,无需更改调用方就可以在程序中引入新的产品类型。

    缺点

    如果有非常多的类型,那么实现的子类会极速地扩张,因此也需要结合其他模式进行优化

    借鉴

    • 《重学Java设计模式》-小傅哥
  • 相关阅读:
    Golang 和稀疏文件
    VScode(Python)使用ssh远程开发(Linux系统树莓派)时,配置falke8和yapf总结避坑!最详细,一步到位!
    什么是RESTful API,以及如何它使用构建 web 应用程序(InsCode AI 创作助手)
    Android 动态更新Menu菜单
    既约分数(蓝桥杯)
    分布式事务Seata源码解析12:全局事务执行流程之全局事务回滚
    深度学习基础知识回顾
    深入理解ThreadLocal
    优秀的推荐系统架构与应用:从YouTube到Pinterest、Flink和阿里巴巴
    使用编辑距离实现英语单词纠错-面向对象实现
  • 原文地址:https://blog.csdn.net/qq_43295093/article/details/126689883