type
status
date
slug
summary
tags
category
icon
password
一、定义

⼯⼚模式⼜称
⼯⼚⽅法模式
,是⼀种创建型设计模式
,其在⽗类中提供⼀个创建对象的⽅法, 允许⼦类 决定实例化对象的类型。这种设计模式也是 Java 开发中最常⻅的⼀种模式,它的主要意图是
定义⼀个创建对象的接⼝
,让其⼦ 类⾃⼰决定实例化
哪⼀个⼯⼚类,⼯⼚模式使其创建过程延迟到⼦类进⾏。简单说就是为了提供代码结构的扩展性,
屏蔽每⼀个功能类中的具体实现逻辑
。让外部可以更加简单的只是知道调⽤即可,同时,这也是去掉众多 ifelse 的⽅式。当然这可能也有⼀些缺点,⽐如需要实现的类⾮常多
,如何去维护,怎样减低开发成本。但这些问题都可以在后续的设计模式结合使⽤中,逐步降低。二、示例:
模拟场景: 1、例如:一般找对象的方式,是通过自己去认识到新的姑娘,类似于姑娘这个对象
需要自己new出来
。假设有一个红娘牵线平台,你只需要说出你的需求,想要什么样的姑娘,平台就会给你连线
出怎么的姑娘。。。 2、例如:商店定义成工厂,我需要在商店里面兑换奖品,奖品的类型包括爱奇艺兑换卡、实物商品、优惠券等等,假设我想要兑换实物商品,我只要在商店里面获取实物商品对象即可,不需要关心实物商品类是怎么创建的。。。爱奇艺卡券类:
IQiYiCard
package com.qf.design.create.factorymethod.entity.card; /** * @description 模拟爱奇艺视频卡,对象类 */ public class IQiYiCard { // 卡券的一些信息 }
获取爱奇艺卡券类:
IQiYiCardService
package com.qf.design.create.factorymethod.entity.card; /** * @description 模拟爱奇艺会员卡服务 */ public class IQiYiCardService { public void grantToken(String bindMobileNumber, String cardId) { System.out.println("模拟发放爱奇艺会员卡一张:" + bindMobileNumber + "," + cardId); } }
优惠券类:
CouponInfo
package com.qf.design.create.factorymethod.entity.coupon; /** * @description 模拟优惠券,对象类 */ public class CouponInfo { // 优惠券的一些信息 }
获取优惠券服务:
CouponService
package com.qf.design.create.factorymethod.entity.coupon; /** * @description 模拟优惠券服务 */ public class CouponService { public CouponResult sendCoupon(String uId, String couponNumber, String uuid) { System.out.println("模拟发放优惠券一张:" + uId + "," + couponNumber + "," + uuid); return new CouponResult("0000", "发放成功"); } }
优惠券返回结果类:
CouponResult
package com.qf.design.create.factorymethod.entity.coupon; /** * @description 优惠券返回结果类 */ public class CouponResult { private String code; // 编码 private String info; // 描述 public CouponResult(String code, String info) { this.code = code; this.info = info; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
商品信息:
GoodsInfo
package com.qf.design.create.factorymethod.entity.goods; /** * @description 模拟商品信息,对象类 */ public class GoodsInfo { }
获取实物商品服务:
GoodsService
package com.qf.design.create.factorymethod.entity.goods; import com.alibaba.fastjson.JSON; /** * @description 模拟实物商品服务 */ public class GoodsService { public Boolean deliverGoods(DeliverReq req) { System.out.println("模拟发货实物商品一个:" + JSON.toJSONString(req)); return true; } }
实物商品服务返回结果:
DeliverReq
package com.qf.design.create.factorymethod.entity.goods; public class DeliverReq { private String userName; // 用户姓名 private String userPhone; // 用户手机 private String sku; // 商品SKU private String orderId; // 订单ID private String consigneeUserName; // 收货人姓名 private String consigneeUserPhone; // 收货人手机 private String consigneeUserAddress; // 收获人地址 public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPhone() { return userPhone; } public void setUserPhone(String userPhone) { this.userPhone = userPhone; } public String getSku() { return sku; } public void setSku(String sku) { this.sku = sku; } public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } public String getConsigneeUserName() { return consigneeUserName; } public void setConsigneeUserName(String consigneeUserName) { this.consigneeUserName = consigneeUserName; } public String getConsigneeUserPhone() { return consigneeUserPhone; } public void setConsigneeUserPhone(String consigneeUserPhone) { this.consigneeUserPhone = consigneeUserPhone; } public String getConsigneeUserAddress() { return consigneeUserAddress; } public void setConsigneeUserAddress(String consigneeUserAddress) { this.consigneeUserAddress = consigneeUserAddress; } }
传统硬编码方式(都在一个类里面实现,多重if else嵌套使用)
发奖请求对象:
AwardReq
package com.qf.design.create.factorymethod.tradition; import java.util.Map; /** * @description 发奖请求对象 */ public class AwardReq { private String uId; // 用户唯一ID private Integer awardType; // 奖品类型(可以用枚举定义);1优惠券、2实物商品、3第三方兑换卡(爱奇艺) private String awardNumber; // 奖品编号;sku、couponNumber、cardId private String bizId; // 业务ID,防重复 private Map<String, String> extMap; // 扩展信息 public String getuId() { return uId; } public void setuId(String uId) { this.uId = uId; } public Integer getAwardType() { return awardType; } public void setAwardType(Integer awardType) { this.awardType = awardType; } public String getAwardNumber() { return awardNumber; } public void setAwardNumber(String awardNumber) { this.awardNumber = awardNumber; } public String getBizId() { return bizId; } public void setBizId(String bizId) { this.bizId = bizId; } public Map<String, String> getExtMap() { return extMap; } public void setExtMap(Map<String, String> extMap) { this.extMap = extMap; } }
发奖结果反馈对象:
AwardRes
package com.qf.design.create.factorymethod.tradition; /** * @description 发奖结果反馈对象 */ public class AwardRes { private String code; // 编码 private String info; // 描述 public AwardRes(String code, String info) { this.code = code; this.info = info; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
模拟发奖服务:
PrizeController
,多重语句if else判断,代码功能实现了,但是不好后续的维护和扩展package com.qf.design.create.factorymethod.tradition; import com.alibaba.fastjson.JSON; import com.qf.design.create.factorymethod.entity.card.IQiYiCardService; import com.qf.design.create.factorymethod.entity.coupon.CouponResult; import com.qf.design.create.factorymethod.entity.coupon.CouponService; import com.qf.design.create.factorymethod.entity.goods.DeliverReq; import com.qf.design.create.factorymethod.entity.goods.GoodsService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @description 模拟发奖服务 */ 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"; } }
测试:
ApiTest
package com.qf.design.create.factorymethod.tradition; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; public class ApiTest { private static Logger logger = LoggerFactory.getLogger(ApiTest.class); public static void main(String[] args) { PrizeController prizeController = new PrizeController(); System.out.println("\\\\r\\\\n模拟发放优惠券测试\\\\r\\\\n"); // 模拟发放优惠券测试 AwardReq req01 = new AwardReq(); req01.setuId("10001"); req01.setAwardType(1); req01.setAwardNumber("EGM1023938910232121323432"); req01.setBizId("791098764902132"); 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("10001"); req02.setAwardType(2); req02.setAwardNumber("9820198721311"); req02.setBizId("1023000020112221113"); req02.setExtMap(new HashMap<String, String>() {{ put("consigneeUserName", "谢飞机"); put("consigneeUserPhone", "15200292123"); put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109"); }}); 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("10001"); req03.setAwardType(3); req03.setAwardNumber("AQY1xjkUodl8LO975GdfrYUio"); AwardRes awardRes03 = prizeController.awardToUser(req03); logger.info("请求参数:{}", JSON.toJSON(req03)); logger.info("测试结果:{}", JSON.toJSON(awardRes03)); } }
工厂方法模式设计
定义一个奖品的接口:
ICommodity
,所有的奖品都实现此接口package com.qf.design.create.factorymethod.design; import java.util.Map; /** * 发送奖品接口 */ public interface ICommodity { /** * private String uId; // 用户唯一ID * private Integer awardType; // 奖品类型(可以用枚举定义);1优惠券、2实物商品、3第三方兑换卡(爱奇艺) * private String awardNumber; // 奖品编号;sku、couponNumber、cardId * private String bizId; // 业务ID,防重复 * private Map<String, String> extMap; // 扩展信息 * @param uId * @param awardNumber * @param bizId * @param extMap */ void sendCommodity(String uId, String commodityId, String awardNumber, String bizId, Map<String, String> extMap); }
爱奇艺卡片:
CardCommodityService
package com.qf.design.create.factorymethod.design; import com.alibaba.fastjson.JSON; import com.qf.design.create.factorymethod.entity.card.IQiYiCardService; 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 awardNumber, String bizId, Map<String, String> extMap) { 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"; } }
优惠卷:
CouponCommodityService
package com.qf.design.create.factorymethod.design; import com.alibaba.fastjson.JSON; import com.qf.design.create.factorymethod.entity.coupon.CouponResult; import com.qf.design.create.factorymethod.entity.coupon.CouponService; 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 awardNumber, 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
package com.qf.design.create.factorymethod.design; import com.alibaba.fastjson.JSON; import com.qf.design.create.factorymethod.entity.goods.DeliverReq; import com.qf.design.create.factorymethod.entity.goods.GoodsService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; public class GoodsCommodityService implements ICommodity { private Logger logger = LoggerFactory.getLogger(CouponCommodityService.class); private GoodsService goodsService = new GoodsService(); @Override public void sendCommodity(String uId, String commodityId, String awardNumber, 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
package com.qf.design.create.factorymethod.design; import com.qf.design.create.factorymethod.entity.card.IQiYiCardService; /** * 实例化工厂 */ public class StoreFactory { public ICommodity getCommodityService(int type){ switch (type){ case 1: return new CouponCommodityService(); case 2: return new GoodsCommodityService(); case 3: return new CardCommodityService(); } throw new RuntimeException("不存在的奖品服务类型"); } public ICommodity getCommodityClass(Class<? extends ICommodity> clazz) throws IllegalAccessException, InstantiationException { if (clazz==null)return null; return clazz.newInstance(); } }
测试:
ApiTest
package com.qf.design.create.factorymethod.design; import org.junit.jupiter.api.Test; import java.util.HashMap; public class ApiTest { @Test public void test_StoreFactory_01() throws Exception { StoreFactory storeFactory = new StoreFactory(); // 1. 优惠券 ICommodity commodityService_1 = storeFactory.getCommodityService(1); commodityService_1.sendCommodity("10001", "EGM1023938910232121323432", null, "791098764902132",null); // 2. 实物商品 ICommodity commodityService_2 = storeFactory.getCommodityService(2); commodityService_2.sendCommodity("10001", "9820198721311", null, null,new HashMap<String, String>() {{ put("consigneeUserName", "谢飞机"); put("consigneeUserPhone", "15200292123"); put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109"); }}); // 3. 第三方兑换卡(模拟爱奇艺) ICommodity commodityService_3 = storeFactory.getCommodityService(3); commodityService_3.sendCommodity("10001", "AQY1xjkUodl8LO975GdfrYUio", null, null,null); } @Test public void test_StoreFactory_02() throws Exception { StoreFactory storeFactory = new StoreFactory(); // 1. 优惠券 ICommodity commodityService = storeFactory.getCommodityClass(CouponCommodityService.class); commodityService.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null,null); // 2. 实物商品 ICommodity commodityService_2 = storeFactory.getCommodityClass(GoodsCommodityService.class); commodityService_2.sendCommodity("10001", "9820198721311", null, null,new HashMap<String, String>() {{ put("consigneeUserName", "谢飞机"); put("consigneeUserPhone", "15200292123"); put("consigneeUserAddress", "吉林省.长春市.双阳区.XX街道.檀溪苑小区.#18-2109"); }}); // 3. 第三方兑换卡(模拟爱奇艺) ICommodity commodityService_3 = storeFactory.getCommodityClass(CardCommodityService.class); commodityService_3.sendCommodity("10001", "AQY1xjkUodl8LO975GdfrYUio", null, null,null); } }
总结: 避免创建者与具体的产品
逻辑耦合
、 满⾜单⼀职责
,每⼀个业务逻辑实现都在所属⾃⼰的类中完成 、 满⾜开闭原则
,⽆需更改使⽤调⽤⽅就可以在程序中引⼊新的产品类型
。但这样也会带来⼀些问题,⽐如有⾮常多的奖品类型,那么实现的⼦类会极速扩张。因此也需要使⽤其他的模式进⾏优化,这些在后续的设计模式中会逐步涉及到- 作者:程序员小舟
- 链接:https://codezhou.top/article/JAVA%E3%80%90%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%91%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章