设计模式汇总
后续增加开源项目中的应用,加深理解
概述
总体来说设计模式分为三大类,创建型,结构型和行为模式。
创建型模式
创建型模式共五种:工厂方法模式、抽象工厂模式、单例模式、原型模式、建造者模式。
结构型模式
结构型模式共七种:组合模式、代理模式、装饰器模式、适配器模式、外观模式、桥接模式、享元模式。
行为模式
行为模式共十一种:访问者模式、中介者模式、观察者模式、命令模式、状态模式、备忘录模式、迭代子模式、责任链模式、解释器模式、策略模式、模板方法模式。
设计模式
工厂方法
工厂方法模式(多态性工厂模式)的核心是一个抽象工厂类。定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
如上图,接口用来定义宏观的业务含义, ExportFactory通过factory()方法创建文件ExportFile。至于具体的业务,如html工厂造html文件,由子类完成。
抽象工厂
抽象工厂,为创建 一组 相关或相互依赖的对象提供一个接口,无需指定它们的具体类。抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是 一个 产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。 在什么情况下应当使用抽象工厂模式取决于这个系统有多个的产品族(每族中有多个产品),而系统只消费其中某一族的产品。
如上图,factory会产生A,B两种产品。用户使用时需要A,B组合一起使用,但不能将两家工厂的产品混着用。
单例模式
单例模式在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。Spring中大多注解默认为单例模式。
![]()
原型模式
原型模式通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。最常用的就是spring实体类为原型模式。
原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。![]()
建造者模式
建造者模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。Protobuf提供的api,zookeeper的客户端框架curator提供的api都是是典型的建造者。
![]()
组合模式
组合对象(composite)由单个对象(leaf)构成且他们实现相同的接口(Component)。
当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。如下图中,composite中就持有一个List的引用。对composite的任何操作都会循环处理此list。![]()
装饰器模式
动态地给一个对象添加一些额外的职责或者行为。装饰模式和静态代理极为相似,但是代理模式具有控制被代理类的访问等性质,而装饰模式紧紧是单纯的扩充被装饰的类。典型应用java的IO api。
![]()
公共接口Component的一个实现类ConcreteComponent有一个Operation;
抽象装饰器(Decorator)维持一个指向构件Component对象的实例。Decorator也实现了Component 的Operation方法。具体的包装类ConcreteDecoratorB新增了一个方法AddedBehavior()。
代理模式
代理模式,隐藏真实对象。给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
静态代理是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。动态代理类的源码是在程序运行期间根据传入的真实类由JVM根据反射等机制动态的生成。![]()
适配器模式
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
![]()
外观模式
外观模式为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。典型应用activiti框架。
![]()
享元模式
享元模式采用一个共享来避免大量拥有相同内容对象的开销。其优点在于它大幅度地降低内存中对象的数量。通过池的概念(连接池,常量池等)尽量的降低新建对象的数量。如下图中,client依赖FlyweightFactory获取ConcreteFlyweight, FlyweightFactory中关联着list of Flyweight。在Java语言中,String类型就是使用了享元模式。
《Head First》中描述如下,如想让某个类的一个实例能用来提供许多“虚拟实例”,就使用蝇量模式。通过TreeManager管理所有Tree的状态数组,实际Tree对象没有状态属性,只有无状态的方法。如现在要display一个树,只需要调用tree对象(唯一的一个对象)的display方法并将其状态参数传入。
![]()
桥接模式
将抽象部分与实现部分分离,使它们都可以独立的变化。抽象类(Abstraction)的成员(Implementor)也是抽象的 这样就可以随意变化了。
![]()
访问者模式
当你想要为一个对象的组合增加新的能力时可以用访问者模式。被访问者(Node) accept visitor时通过回调visitor.visit方法,告诉visitor 此node的引用,visit方法里就可以获取node的任何信息。使得新增新的访问操作变得更加简单。
![]()
观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。观察者就是常说的监听器。
![]()
备忘录模式
备忘录对象(memento)是用来存储另外一个对象(originator)内部状态的对象。备忘录模式的用意是在不破坏封装的条件下,client将一个对象(originator)的状态捕捉(通过其createMemento()方法),并调用caretaker.saveMemento存储起来,从而在将来某些时候,originator可以把memento这个对象取回来并根据memento还原到之前的状态。
状态模式
状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。如下图,context.request()是通过state.handle()实现的,当context的state发生变化,request行为也改变了。
![]()
命令模式
命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
![]()
策略模式
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。如系统可以根据用户不同的配置来执行不同策略,而不用去更改代码实现。
解释器模式
解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。如下图,new Not(x); 其intercept()方法可能为 return !x;
具体可参照
http://www.cnblogs.com/java-my-life/archive/2012/06/19/2552617.html![]()
中介者模式
用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。如下图,每个具体的同事都拥有中间者,而中间者拥有同事间的关系。
![]()
责任链模式
在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。实际应用中经常并不是直接由handler来维护其下一个的引用,通常是由一个pipeline的对象来维护这些handler的前后关系。Netty,tomcat都由类似的结构。
![]()
迭代子模式
迭代子模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。如下图,client通过aggreate创建Iterator,然后通过iterator就可以遍历元素了。
![]()
Iterator模式适用于对聚合对象的多种遍历,为遍历不同的聚合结构提供一个统一的接口。
模板方法模式
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使的子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
![]()
设计模式6大原则
- 单一职责原则(Single Responsibility Principle),一个类只负责一项职责。
- 里氏替换原则(Liskov Substitution Principle),子类可以扩展父类的功能,但不能改变父类原有的功能。
- 依赖倒置原则(Dependence Inversion Principle),高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。依赖倒置原则的中心思想是面向接口编程。
- 接口隔离原则(Interface Segregation Principle),客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
- 迪米特法则(Law Of Demeter),一个对象应该对其他对象保持最少的了解。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
开闭原则(Open Close Principle),一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
综述,单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。
注:此文转自网友williamxww1,特别感谢williamxww1该文的版权声明:随便拿