常用的23种设计模式
分类 |
设计模式 |
创建型 |
工厂方法模式(FactoryMethod)、抽象工厂模式(AbstractFactory)、建造者模式(Builder)、原型模式(Prototype)、单例模式(Singleton) |
结构型 |
适配器模式(Adapter)、桥接模式(Bridge)、组合模式(Composite)、装饰器模式(Decorator)、门面模式(Facade)、享元模式(Flyweight)、代理模式(Proxy) |
行为型 |
解释器模式(Interpreter)、模板方法模式(TemplateMethod)、责任链模式(ChainofResponsibility)、命令模式(Command)、迭代器模式(Iterator)、调解者模式(Mediator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式(State)、策略模式(Strategy)、访问者模式(Visitor) |
设计模式之间的关系
1.实现关系:继承抽象类
用一条带虚线的空心箭头表示
2.泛化关系:继承非抽象类
用一条带实线的空心箭头表示
3.聚合关系:用于表示实体对象之间的关系,表示整体由部分构成,其中的整体和部分不是强依赖的,即使整体不存在了,部分仍然存在。
比如,一辆汽车,它由发动机、轮胎以及其它零件等组成。但是将它拆成各种零件以后,这辆汽车就不存在了,但是发动机、轮胎以及其它零件还是存在的。
用一条带实线的空心菱形箭头表示
4.组合关系:同样表示整体由部分构成的语义,其中的整体和部分是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也不存在了。
比如,如果公司倒闭了,那公司的各个部门也将不存在了。
用一条带实线的实心菱形箭头表示
5.关联关系:描述不同类的对象之间的结构关系。它是一种静态关系,通常与运行状态无关,一般由常识等因素决定的。它一般用来定义 对象之间静态的、天然的结构;所以,关联关系是一种“强关联”的关系。
比如,有一个类Person它有name、age、id(身份证号码)等属性;另一个类IdCard(身份证类)它有picutre、homeAddr、id(身份证号码)等属性。那么它们的对象可以通过id相互关联起来,具体描述一个人的不同方面。感觉有点像数据库不同表之间,根据字段相关联的意思。
用一条实线表示
6.依赖关系:依赖关系描述一个对象在运行期间用到另一个对象的关系;是一种临时性的关系,通常在运行期间产生,并且随着运行时的变 化,依赖关系可能发生变化。依赖也有方向,双向依赖是一种非常糟糕的结构,应该始终保持单向依赖,避免双向依赖。最终代 码中,依赖关系体现为类构造方法和类方法的传入参数,依赖关系除了临时知道对象外,还会使用对方的方法和属性。
用一条带虚线的箭头表示
-<作者:小傅哥 链接:https://bugstack.cn 来源:bugstack虫洞栈>
-学习记录用
一:创建型模式
⼯⼚⽅法
抽象⼯⼚
建造者
原型模式
单例模式
1.设计模式原则
设计模式遵循六大原则
单一职责(一个类和方法只做一件事)
里氏替换(多态,子类可扩展父类)
依赖倒置(细节依赖抽象,下层依赖上层)
接口隔离(建立单一接口)
迪米特原则(最少知道,降低耦合)
开闭原则(抽象架构,扩展实现)
会在具体的设计模式章节中,进行体现。
工厂模式
⼯⼚模式⼜称⼯⼚⽅法模式,是⼀种创建型设计模式,其在⽗类中提供⼀个创建对象的⽅法,允许⼦类
决定实例化对象的类型
类型 |
接口 |
优惠券 |
CouponResult sendCoupon(String uId, String couponNumber, String uuid) |
实物奖品 |
Boolean deliverGoods(DeliverReq req) |
兑换卡 |
void grantToken(String bindMobileNumber, String cardId) |
3种业务实现,以往我们都是根据不同的业务类型判断,调用不同的接口实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| 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); 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("consigneeUserAddr ess")); 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"; } }
|
但是一但一个业务会增加处理逻辑,就要在一个方法内添加,判断,处理异常等,违反单一职责,开闭原则
写mock测试时,就会发现调用一个接口的逻辑3遍,写了很多重复代码
工厂模式重构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| itstack-demo-design-1-02 !"" src #"" main $ !"" java $ !"" org.itstack.demo.design $ #"" store $ $ #"" impl $ $ $ #"" CardCommodityService.java $ $ $ #"" CouponCommodityService.java $ $ $ !"" GoodsCommodityService.java $ $ !"" ICommodity.java $ !"" StoreFactory.java !"" test !"" java !"" org.itstack.demo.design.test !"" ApiTest.java
|
它看上去清晰了、这样分层可以更好扩展了、似乎可以想象到每⼀个类做了什么
定义一个父接口用来实现
1 2 3 4
| public interface ICommodity { void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception; }
|
定义三种业务类型的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 优惠券
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()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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"; } }
|
工厂类
1 2 3 4 5 6 7 8 9 10
| 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("不存在的商品服务类型"); } }
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public void test_commodity() throws Exception { StoreFactory storeFactory = new StoreFactory(); ICommodity commodityService_1 = storeFactory.getCommodityService(1); commodityService_1.sendCommodity("10001", "EGM1023938910232121323432", "791098764902132", null); ICommodity commodityService_2 = storeFactory.getCommodityService(2);
Map<String,String> extMap = new HashMap<String,String>(); extMap.put("consigneeUserName", "谢⻜机"); extMap.put("consigneeUserPhone", "15200292123"); extMap.put("consigneeUserAddress", "吉林省.⻓春市.双阳区.XX街道.檀溪苑⼩ 区.#18-2109");
commodityService_2.sendCommodity("10001","9820198721311","102300002011222 1113", extMap); ICommodity commodityService_3 = storeFactory.getCommodityService(3);
commodityService_3.sendCommodity("10001","AQY1xjkUodl8LO975GdfrYUio",null ,null); }
|
感觉比较像策略模式吧,但是看过之后确实觉得一些业务代码是可以这么优化,省去很多维护的成本