zoukankan      html  css  js  c++  java
  • 设计模式-创建者模式-工厂方法模式

    工厂方法模式

    案例:模拟发放奖品

    三种奖品:优惠券,实物商品,爱奇艺兑换卡

    未重构前的结构:

    其中针对不同的奖品,会有不同逻辑的service方法,每个service方法的入参和返回值都不一样

    • 模拟实物商品服务(返回是否发放成功的标志)

      public class GoodsService {
      
          public Boolean deliverGoods(DeliverReq req) {
              System.out.println("模拟发货实物商品一个:" + JSON.toJSONString(req));
              return true;
          }
      
      }
      
    • 模拟优惠券服务(返回针对优惠券的返回结果:code,info)

      public class CouponService {
      
          public CouponResult sendCoupon(String uId, String couponNumber, String uuid) {
              System.out.println("模拟发放优惠券一张:" + uId + "," + couponNumber + "," + uuid);
              return new CouponResult("0000", "发放成功");
          }
      
      }
      
    • 模拟爱奇艺会员卡服务(只输出结果,无返回值)

      public void grantToken(String bindMobileNumber, String cardId) {
          System.out.println("模拟发放爱奇艺会员卡一张:" + bindMobileNumber + "," + cardId);
      }
      
    未重构前处理逻辑的代码结构

    AwardReq是入参,统一奖品的信息形式

    AwardRes是出参,统一发放奖品的返回结果形式

    PrizeController的模拟发放奖品的代码逻辑
    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";
        }
    
    }
    

    通过AwardReq入参的awardType来判断发放什么奖品,然后执行对应奖品的对应的service服务方法

    可以看出,如果只是通过iflese判断来执行不同的service方法,每一次增加一种奖品类型,都要在controller方法里新增一个判断并且在判断里也要重新填写新的service的方法,并且还要增加针对新奖品的service方法的逻辑

    重构后的代码结构如下:

    • 首先统一service接口

      public interface ICommodity {
      
          void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception;
      
      }
      
    • 然后分别针对不同的奖品来实现上述service接口,在这些实现方法里注入各自的单独的service方法,然后在实现方法里调用这些service方法

      • 发放优惠券奖品:

        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 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";
            }
        
        }
        
      • 发放实物奖品:

        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";
            }
        
        }
        
      • 创建工厂StoreFactory,在工厂里边装载上述的统一接口:Icommodity,然后根据入参的type判断返回什么具体的奖品服务实现方法

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

      经过工厂方法重构之后,易于扩展,新增一个奖品类型,只需要新增一个实现Icommodity的服务方法,然后在工厂里增加一个判断返回该服务类即可,优点是: 避免创建者与具体的产品逻辑耦合 、 满足单一职责,每⼀个业务逻辑实现都在所属⾃自⼰己的类中完成 、 满⾜足开闭原则

  • 相关阅读:
    解决端口被占用
    Oracle查询所有表的字段明细
    Spring cron表达式
    Java爬取12306余票
    Activiti工作流框架——快速上手
    ERROR 1045 (28000): Access denied for user 'xxx'@'localhost' (using password: YES)【奇葩的bug】
    一分钟学会JavaMail(假)__手动滑稽
    通过Servlet实现汉字验证码
    使用ServletContext对象读取资源文件
    编写一个简单的java服务器程序
  • 原文地址:https://www.cnblogs.com/RealGang/p/14611128.html
Copyright © 2011-2022 走看看