工厂模式
工厂模式也是最常用的模式之一,是创建型模式的一种。父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
工厂模式的思想是提供一个创建对象的结构,让子类决定去实例化哪一个工厂,并隐蔽了具体的实现逻辑。
生活中最常见的就是购物,当我们去买东西时,去不同的品牌店就可以买到对应的品牌,我们不用考虑它的实现过程。还有就是我们在网上参加活动,中奖后可以选择不同的奖品,这里也可以用到工厂模式来实现。
多类型奖品发放实现工厂模式
假设商品提供三种接口
//优惠券接口
CouponResult sendCoupon(String uId, String couponNumber, String uuid);
//实物接口
Boolean deliverGoods(DeliverReq req);
//第三方兑换券接口
void grantToken(String phoneNumber, String cardId);
定义一个共同的接口,所有商品走这个接口来保证参数的统一性。
public interface Commodity {
/**
*
* @param uid 用户id
* @param commodityId 商品id
* @param bizId 业务id
* @param extData 其他信息
*/
void sendCommodity(String uid, String commodityId, String bizId, Map<String,String> extData);
}
实现优惠券发放接口
public class CouponCommodityService implements Commodity {
private Logger logger = LoggerFactory.getLogger(CouponCommodityService.class);
private CouponService couponService = new CouponService();
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extData) throws Exception {
CouponResult couponResult = couponService.sendCoupon(uId, commodityId, bizId);
logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extData:{}", uId, commodityId, bizId, JSON.toJSON(extData));
logger.info("测试结果[优惠券]:{}", JSON.toJSON(couponResult));
if (!"0000".equals(couponResult.getCode())) throw new RuntimeException(couponResult.getInfo());
}
}
实现实物发放接口
public class GoodsCommodityService implements Commodity {
private Logger logger = LoggerFactory.getLogger(GoodsCommodityService.class);
private GoodsService goodsService = new GoodsService();
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extData) throws Exception {
DeliverReq deliverReq = new DeliverReq();
deliverReq.setUserName(queryUserName(uId));
deliverReq.setUserPhone(queryUserPhoneNumber(uId));
deliverReq.setSku(commodityId);
deliverReq.setOrderId(bizId);
deliverReq.setConsigneeUserName(extData.get("consigneeUserName"));
deliverReq.setConsigneeUserPhone(extData.get("consigneeUserPhone"));
deliverReq.setConsigneeUserAddress(extData.get("consigneeUserAddress"));
Boolean isSuccess = goodsService.deliverGoods(deliverReq);
logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{} extData:{}", uId, commodityId, bizId, JSON.toJSON(extData));
logger.info("测试结果[优惠券]:{}", isSuccess);
if (!isSuccess) throw new RuntimeException("实物商品发放失败");
}
private String queryUserName(String uId) {
return "李华";
}
private String queryUserPhoneNumber(String uId) {
return "123456789";
}
}
实现第三方兑换接口
public class CardCommodityService implements Commodity {
private Logger logger = LoggerFactory.getLogger(CardCommodityService.class);
private IQiYiCardService iQiYiCardService = new IQiYiCardService();
public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extData) throws Exception {
String mobile = queryUserMobile(uId);
iQiYiCardService.grantToken(mobile, bizId);
logger.info("请求参数[视频兑换卡] => uId:{} commodityId:{} bizId:{} extData:{}", uId, commodityId, bizId, JSON.toJSON(extData));
logger.info("测试结果[视频兑换卡]:success");
}
private String queryUserMobile(String uId) {
return "123456789";
}
}
创建工厂(看样子有点像简单工厂)
public class StoreFactory {
public ICommodity getCommodityService(Integer commodityType) {
switch(commodityType){
case 1:return new CouponCommodityService();
case 2:return new GoodsCommodityService();
case 3:return new CardCommodityService();
default:
throw new RuntimeException("不存在的商品服务类型");
}
}
测试
@Test
public void test_commodity() throws Exception {
StoreFactory storeFactory = new StoreFactory();
Commodity commodityService = storeFactory.getCommodityService(1);
commodityService_1.sendCommodity("001", "EST43254264542", "47443272432888865", null);
}
模拟发放优惠券一张:001,EST43254264542,47443272432888865
请求参数[优惠券] => uId:001 commodityId:EST43254264542 bizId:47443272432888865 extData
测试结果[优惠券]:{"code":"0000","info":"发放成功"}
总结:工厂模式避免创建者与具体的产品逻辑耦合 、 满足单⼀职责,每⼀个业务逻辑实现都在所属自己的类中完成 、 满足开闭原则,无需更改使用调用方就可以在程序中引入新的产品类型 。但这样也会带来⼀些问题,比如有非常多的奖品类型,那么实现的子类会极速扩张。因此也需要使用其他的模式进行优化,这些在后续的设计模式中会逐步涉及到。