Java-Design-Pattern 工厂方法模式

48 阅读2分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

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

意图

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

案例

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

商品类型接口
实物商品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;
    }

image.png

设计模式实现

/**
 * Description:发奖接口,无论是什么商品类型都需要实现这个接口,统一出入参
 */
public interface ICommodity {
​
    /**
     * @param uId 用户ID
     * @param commodityId 商品ID
     * @param bizId 业务ID
     * @param extParam 扩展字段
     */
    void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extParam) throws Exception;
​
}
/**
 * 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("该商品类型不支持");
    }
}

image.png

优点

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

缺点

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

借鉴

  • 《重学Java设计模式》-小傅哥