工厂模式的介绍
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式
工厂模式又称工厂方法模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
这种设计模式也是 Java 开发中最常见的一种模式,它的主要意图是定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行
那是不是当多个对象,继承同一个父类,可以实例化一个工厂,用于生产这些对象呢?
分类
- 简单工厂(一个普通类)
public class Factory{
public static ISample creator(int which){
// 判断返回对象
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
- 抽象工厂(一个抽象类)
//抽象类
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
//实现一个工厂
public class SimpleFactory extends Factory{
public Sample creator(){
.........
return new SampleA
}
public Sample2 creator(String name){
.........
return new Sample2A
}
}
//实现一个工厂
public class BombFactory extends Factory{
public Sample creator(){
......
return new SampleB
}
public Sample2 creator(String name){
......
return new Sample2B
}
}
案例(来自与小傅哥的重学java设计模式)
简单工厂
-
场景:积分兑换中的发放多种类型商品,有优惠券,实物,爱奇艺卡
-
代码:
- 创建对象:优惠卷,实物,爱奇艺
- 使用:
-
普通做法,通过if判断:
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; }
-
工厂模式
- 创建商品接口,创建三个商品(消费卷,实物,爱奇艺)实现这个接口
public interface ICommodity { //发送 void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception; }
- 实现类
//实物 public class GoodsCommodityService implements ICommodity{} //优惠卷 public class CouponCommodityService implements ICommodity{} //爱奇艺 public class CardCommodityService implements ICommodity{}
- 创建一个工厂
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("不存在的商品服务类型"); } }
- 使用
@Test public void test_commodity() throws Exception { StoreFactory storeFactory = new StoreFactory(); // 1. 优惠券 ICommodity commodityService_1 = storeFactory.getCommodityService(1); commodityService_1.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null); // 第三方兑换卡(爱奇艺) ICommodity commodityService_3 = storeFactory.getCommodityService(3); commodityService_3.sendCommodity("10001","AQY1xjkUodl8LO975GdfrYUio",null,null); // 实物也是这个写,标准统一,返回参数也一样 }
-
-
总结
避免创建者与具体的产品逻辑耦合、满足单一职责,每一个业务逻辑实现都在所属自己的类中完成、满足开闭原则,无需更改使用调用方就可以在程序中引入新的产品类型
---- 小傅哥- 个人理解:
- 进行了封装,统一了入参、统一了结果。只要增加类,对于使用方基本无感,只要变更传参就行。
- 就如上例子,如果要添加一个类型,
- if 案例的修改:
- 新增一个类型类
- 要在这个awardToUser方法还要添加一个else,
- 调用方还要了解刚新增的类
- 使用工厂模式
- 新增一个类,实现 ICommodity
- 工厂方法添加一个刚实现的类
- 调用方不改变,参数改下就行
- if 案例的修改:
- 感谢
小傅哥的重学java设计模式
还有 研磨设计模式(链接) 这本书