class="MsoTitle">设计模式实战
什么是设计模式:
??? 代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
?
使用设计模式的目的:
?? 代码复用、增加代码可维护性的目的、代码风格优雅。
?
OOD七大原则:
?
?? 面向对象设计(Object-Oriented Design,OOD)有七大原则。
开-闭原则
?
Open-Close Principle(OCP),即开-闭原则。开,指的是对扩展开放,即要支持方便地扩展;闭,指的是对修改关闭,即要严格限制对已有内容的修改。开-闭原则是最抽象也是最重要的OOD原则。
?
里氏替换原则
?
Liskov Substitution Principle(LSP),即里氏替换原则。该原则规定“子类必须能够替换其父类,否则不应当设计为其子类”。换句话说,父类出现的地方,都应该能由其子类代替。所以,子类只能去扩展基类,而不是隐藏或者覆盖基类。
?
依赖倒置原则
?
Dependence Inversion Principle(DIP),依赖倒置原则。它讲的是“设计和实现要依赖于抽象而非具体”。一方面抽象化更符合人的思维习惯;另一方面,根据里氏替换原则,可以很容易将原则的抽象替换为扩展后的具体,这样可以很好的支持开-闭原则。
?
接口隔离原则
?
Interface Segration Principle(ISP),接口隔离原则,“将大的接口打散成多个小的独立的接口”。由于Java类支持实现多个接口,可以很容易的让类具有多种接口的特征,同时每个类可以选择性地只实现目标接口。
?
单一职责原则
?
Single Responsibility Principle(SRP),单一职责原则。它讲的是,不要存在多于一个导致类变更的原因,是高内聚低耦合的一个体现。
?
迪米特法则/最少知道原则
?
Law of Demeter or Least Knowledge Principle(LoD or LKP),迪米特法则或最少知道原则。它讲的是“一个对象就尽可能少的去了解其它对象”,从而实现松耦合。如果一个类的职责过多,由于多个职责耦合在了一起,任何一个职责的变更都可能引起其它职责的问题,严重影响了代码的可维护性和可重用性。
?
合成/聚合复用原则
?
Composite/Aggregate Reuse Principle(CARP / CRP),合成/聚合复用原则。如果新对象的某些功能在别的已经创建好的对象里面已经实现,那么应当尽量使用别的对象提供的功能,使之成为新对象的一部分,而不要再重新创建。新对象可通过向这些对象的委派达到复用已有功能的效果。简而言之,要尽量使用合成/聚合,而非使用继承。《Java设计模式(九) 桥接模式》中介绍的桥接模式即是对这一原则的典型应用。
?
模式分类:
创建型:工厂方法、抽象工厂、单例、建造者、原型
结构型:适配器、装饰器、代理、外观、桥接、组合、享元
行为型:策略、模版方法、观察者、迭代、责任链、命令模式、状态、访问者、中介者、解释器
?
代理模式(proxy)
?
?
1、RealSubject 是委托类,Proxy 是代理类;
2、Subject 是委托类和代理类的接口;
3、request() 是委托类和代理类的共同方法;
?
项目中典型事例:
??? 在自贩机的支付工程,我们就使用此模式,废话不多少说了直接上代码
Proxy:
public class PaymentProxy { ??? @Autowired ??? private PaymentServiceFacade paymentServiceFacade; ??? @RequestMapping(value="/pay") ??? public void pay(HttpServletRequest request, HttpServletResponse response) throws Exception { ??????? String payPlatform = request.getParameter("payPlatform"); ??????? paymentServiceFacade.proxy(payPlatform).pay(request,response); ??? } ??? @RequestMapping(value="/notify",method = RequestMethod.POST) ??? public void notify(HttpServletRequest request, HttpServletResponse response) throws Exception { ??????? String payPlatform = request.getParameter("payPlatform")==null?"tenpay":request.getParameter("payPlatform"); ????? ??paymentServiceFacade.proxy(payPlatform).notify(request,response); ??? } ??? @RequestMapping(value="/confirmPay",method = RequestMethod.POST) ??? public void confirmPay(String payPlatform ,String out_trade_no,int timeout ) throws Exception { ??????? paymentServiceFacade.proxy(payPlatform).confirmPay(out_trade_no,System.currentTimeMillis()+timeout*60*1000); ??? } ??? @RequestMapping(value="/refund",method = RequestMethod.POST) ??? public void refund(HttpServletRequest request, HttpServletResponse response ) throws Exception { ??????? String payPlatform = request.getParameter("payPlatform"); ??????? paymentServiceFacade.proxy(payPlatform).refund(request,response); ??? } }
?
Subject:
public interface PaymentService { ??? /** ???? * 支付 ???? * @param request ???? * @param response ???? */ ??? void pay(HttpServletRequest request, HttpServletResponse response) throws Exception; ??? /** ???? * 接受第三方支付结果 ???? * @param request ???? * @param response ???? */ ??? void notify(HttpServletRequest request, HttpServletResponse response) throws Exception; ??? /** ???? * 退款 ???? * @param request ???? * @param response ???? * @throws Exception ???? */ ??? void refund(HttpServletRequest request, HttpServletResponse response) throws Exception; ??? /** ???? * 确认订单状态(主动轮询第三方平台查询结果) ? ???* @param out_trade_no 订单号 ???? * @param stopDatetime 超过此时间后不再查询结果 ???? */ ??? void confirmPay(String out_trade_no, long stopDatetime) throws Exception; }
RealSubject :
?
?
?
?
?
建造者模式(builder)
?
建造者模式通常包括下面几个角色:
1. builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
2. ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
3. Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
4. Product:要创建的复杂对象。
?
项目中典型事例:
mybatis的反向生产的查询条件建造者类,比如表名为:vem_file的一张表,会生成VemFileExample,GeneratedCriteria,Criteria。上图中Director(指挥者)对应的就是VemFileExample类,Builder对应的是GeneratedCriteria,ConcreteBuilder对应的是Criteria。
?
?
使用场景
??? 创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。
?
?
?
从类图中我们可以看到,观察者的内容能够获得较快的更新的原因是因为被观察者在数据有修改的时候去及时通知所有的观察者了
?
项目中典型事例:
??? 例如自贩机系统,自贩机会定时上报故障和机器的状态指标,这些指标就是被观察者(Subject),现在有几种告警手段:短信、邮件、微信(这些都是观察者),有故障和机器状态变化就会通知观察者。
?
使用场景:
(1) 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用。?
? ? ? ? (2) 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。