摘录一些设计模式的要点,原博主有精细的分类说明,推荐大家去学习一下,地址:http://www.cnblogs.com/jqbird/tag/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/
1).抽象工厂模式(Abstract factory):
原理:
抽象工厂模式的一个主要目的是把所生成的具体类相分离,这些类的实际名称被隐藏在工厂中,在客户级不必了解。
JDK中的此模式应用:
java.util.Calendar#getInstance()
java.util.Arrays#asList()
java.util.ResourceBundle#getBundle()
java.sql.DriverManager#getConnection()
java.sql.Connection#createStatement()
java.sql.Statement#executeQuery()
java.text.NumberFormat#getInstance()
javax.xml.transform.TransformerFactory#newInstance()
应用场合:
1.一个系统要独立于它的产品的创建、组合和表示时。
2.一个系统要由多个产品系列中的一个来配置时。
3.当你强调一系列相关的产品对象的设计以便进行联合使用时。
4.当你提供一个产品类库,而只想显示他们的接口而不是实现时。
2).建造者/生成器模式 (Builder):
原理:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
主要用来简化一个复杂的对象的创建。
JDK中的此模式应用:
java.lang.StringBuilder#append()
java.lang.StringBuffer#append()
java.sql.PreparedStatement
javax.swing.GroupLayout.Group#addComponent()
应用场合:
1.当创建复杂对象的算法应该独立于该对象的组成部分及他们的装配方式时。
2.当构造过程必须允许被构造的对象有不同的表示时。
3).工厂方法模式 (Factory Method):
原理:
工厂方法通过一个抽象类实现了所有对产品的加工操作代码,唯独将产品的构建方法写成抽象方法。
继承这个抽象类的具体类只重写其构建方法,这样就实现了对于不同被构建产品复用相同的加工操作逻辑
简单来说,按照需求返回一个类型的实例。
JDK中的此模式应用:
java.lang.Proxy#newProxyInstance()
java.lang.Object#toString()
java.lang.Class#newInstance()
java.lang.reflect.Array#newInstance()
java.lang.reflect.Constructor#newInstance()
java.lang.Boolean#valueOf(String)
java.lang.Class#forName()
应用场合:
需要在子类中才能决定实例化哪个被操作对象,同时这些被操作对象又复用相同操作逻辑的场合。
4). 原型模式 (Prototype):
原理:
使用自己的实例创建另一个实例。有时候,创建一个实例然后再把已有实例的值拷贝过去,是一个很复杂的动作。
所以,使用这个模式可以避免这样的复杂性。
JDK中的此模式应用:
java.lang.Object#clone()
java.lang.Cloneable
应用场合:
1.当一个系统应该独立于它的产品创建、构成和表示时。
2、当要实例化的类是在运行时刻指定时,例如通过动态装载。
3、为了避免创建一个与产品类层次平行的工厂类层次时。
4、当一个类的实例只能有几个不同状态组合中的一种时。
5).单例模式 (Singleton):
原理:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但他不能防止你实例化多个对象,一个最好的办法就是,让这个类自身保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问改实例的方法。
JDK中的此模式应用:
java.lang.Runtime#getRuntime()
java.awt.Toolkit#getDefaultToolkit()
java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
java.awt.Desktop#getDesktop()
应用场合:
1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
2.当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
6).适配器模式 (Adapter):
原理:
将一个类的接口转换成用户希望的另一个接口,使原本由于接口不兼容而不能一起工作的那些类可以一起工作。
JDK中的此模式应用:
java.util.Arrays#asList()
javax.swing.JTable(TableModel)
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)
javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()
应用场合:
1.你想使用一个已经存在的类,而它的接口不符合你的要求。
2.你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
3.(仅适用于对象adapter),你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配他们的接口。对象适配器可以适配它的父类接口
7).桥接模式 (Bridge):
原理:
把抽象和实现解藕,于是接口和实现可在完全独立开来。
JDK中的此模式应用:
AWT (提供了抽象层映射于实际的操作系统)
JDBC
应用场合:
1.你不希望在抽象和它的实现部分有一个固定的绑定关系。例如这种情况可能是因为程序在运行时刻部分应用可以被选择或者切换。
2.类的抽象以及它的实现都可以通过生成子类的方法加以扩充。
3.对一个抽象的实现部分的修改应对客户不产生影响,即客户端的代码不必重新编译。
4.你想在多个对象之间共享实现,但是同时要求客户并不知道这一点
8).组合模式 (Composite):
原理:
将对象组合成树形结构以表示"部分-整体"的层次结构。"Composite"使得用户对单个对象和组合对象的使用具有一致性。
JDK中的此模式应用:
javax.swing.JComponent#add(Component)
java.awt.Container#add(Component)
java.util.Map#putAll(Map)
java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)
应用场合:
1.你想用部分-整体结构层次。
2.你希望用户忽略组合对象与单个对象的不同,用户将统一的使用组合结构中的所有对象。
9).装饰模式 (Decorator):
原理:
动态地给一个对象添加一些额外的职责,比单纯的继承更为灵活合理.
JDK中的此模式应用:
java.io.BufferedInputStream(InputStream)
java.io.DataInputStream(InputStream)
java.io.BufferedOutputStream(OutputStream)
java.util.zip.ZipOutputStream(OutputStream)
java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
应用场合:
比如java的System.IO各种输出就是通过装饰模式来实现的,还有一些日志类,动态的添加日志记录的功能,将耦合度降到最低。
10).外观模式 (Facade):
原理:
为子系统的一组接口提供一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
JDK中的此模式应用:
java.lang.Class
javax.faces.webapp.FacesServlet
应用场合:
1.当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用都会产生更 多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子类的的用户带来一些 使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制 性的用户可以越过Facade层。
2.客户端程序与抽象类的实现部分存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提 高子系统的独立性和可移植性。
3.当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统的每层的入口点。如果子系统之间是相互依赖的, 你可以让他们仅通过facade进行通讯,从而简化了他们之间的依赖关系。
11).享元模式 (Flyweight):
原理:
运用共享技术有效地支持大量细粒度的对象。
JDK中的此模式应用:
java.lang.Integer#valueOf(int)
java.lang.Boolean#valueOf(boolean)
java.lang.Byte#valueOf(byte)
java.lang.Character#valueOf(char)
应用场合:
1.一个应用程序使用了大量的对象。
2.完全由大量的对象,造成很大的存储开销。
3.对象的大多数状态都可变为外部状态。
4.如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
5.应用程序不依赖于对象标识,由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
12).代理模式 (Proxy):
原理:
为其他对象提供一种代理以控制对这个对象的访问,简单的来说调用这个类的同时其实里面是别的类在干事。
JDK中的此模式应用:
java.lang.reflect.Proxy
RMI
应用场合:
1.远程代理:也就是为一个对象在不同的地址空间提供局部代表,这样可以影藏一个对象存在于不同地址空间的事实,比如.net里的webservice。
2.虚拟代理:根据需要将一个资源消耗很大的或者比较复杂的对象延迟到真正需要时才创建,比如延迟加载图片,优先加载文字
3.保护代理:控制对一个对象的访问权限,用于对象有权限设置的时候
4.智能引用:当调用真实对象时,代理处额外的事情来,提供额外的服务,如计算对象真实的引用次数,这样对象没有引用时可以自动释放它,通过代理访问一个对象时做一些额外的内务处理。
13).职责链模式 (Chain of responsibility):
原理:
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链。
并沿着这条链传递该请求,直到有一个对象处理它为止。在这个链上的所有的对象有相同的接口(抽象类)但却有不同的实现。
JDK中的此模式应用:
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
应用场合:
1.有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
2.你想在不明确指定接受者的情况下,向多个对象中的一个提交请求。
3.处理一个请求的对象集合应被动态指定。
14).命令模式 (Command):
原理:
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
JDK中的此模式应用:
java.lang.Runnable
javax.swing.Action
应用场合:
1.抽象出待执行的动作以参数化某对象。
2.在不同的时刻指定、排列和执行请求。
3.支持取消操作。
4.支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。
5.用构建在原语操作上的高层操作构造一个系统。
15).解释器模式 (Interpreter):
原理:
一个语法解释器的模式。
JDK中的此模式应用:
java.util.Pattern
java.text.Normalizer
java.text.Format
应用场合:
当一个语言需要解释执行,并且你可以将该语句中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好。
1.该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。
2.效率不是一个关键问题,最高效的解释器通常不是通过直接解析语法分析树实现的,而是首先将他们转换成另一种形式。
16).迭代器模式 (Iterator):
原理:
提供一种一致的方法来顺序遍历一个容器中的所有元素。
JDK中的此模式应用:
java.util.Iterator
java.util.Enumeration
应用场合:
1.访问一个聚合对象的内容而无需暴露它的内部表示。
2.支持对聚合对象的多种遍历。
3.为遍历不同的聚合结构提供一个统一的接口(即,多态迭代)。
17).中介者模式 (Mediator):
原理:
用中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以对立地改变他们之间的交互。用来减少对象单的直接通讯的依赖关系。使用一个中间类来管理消息的方向。
JDK中的此模式应用:
java.util.Timer
java.util.concurrent.Executor#execute()
java.util.concurrent.ExecutorService#submit()
java.lang.reflect.Method#invoke()
应用场合:
1.一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
2.一个对象引用很多其他对象并直接与这些对象通信,导致难以复用该对象。
3.想定制一个分部在多个类中的行为,而又不想生成太多的子类。
18).备忘录模式 (Memento):
原理:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。给一个对象的状态做一个快照。Date类在内部使用了一个long型来做这个快照。
JDK中的此模式应用:
java.util.Date
java.io.Serializable
应用场合:
1.必须保存一个对象在某一时刻(部分)的状态,这样以后需要时它才能恢复到先前的状态。
2.如果用一个接口来让其他对象直接得到这个状态,将会暴露对象的实现细节并破坏对象的封装性。
19).观察者模式 (Observer):
原理:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
JDK中的此模式应用:
java.util.EventListener
javax.servlet.http.HttpSessionBindingListener
javax.servlet.http.HttpSessionAttributeListener
javax.faces.event.PhaseListener
应用场合:
1.当一个对象有两个方面,其中一个方面依赖于另一个方面。将二者封装在独立的对象中以使他们可以各自独立的改变和复用。
2.当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
3.当一个对象必须通知其他对象,而又不能假定其他对象是谁。
20).状态模式 (State):
原理:
这个模式允许你可以在运行时很容易地根据自身内部的状态改变对象的行为。
JDK中的此模式应用:
java.util.Iterator
javax.faces.lifecycle.LifeCycle#execute()
应用场合:
1.当一个对象的转换条件表达式过于复杂时,通常这个状态由一个或者多个枚举表示,通常有多个操作包含这一相同的的条件结构,state模式将一个条件分支放到一个类中,这使得你可以根据对象自身的情况将对象的状态作为对象,这一对象不依赖于其他对象而独立变化,把状态的判断逻辑放到表示不同状态的一系列类中。
2.一个对象的行为取决于它的状态,并且它必须在运行时根据状态立即改变行为。
21).策略模式 (Strategy):
原理:
定义一组算法,并把其封装到一个对象中。然后在运行时,可以灵活的使用其中的一个算法。
JDK中的此模式应用:
java.util.Comparator#compare()
javax.servlet.http.HttpServlet
javax.servlet.Filter#doFilter()
应用场合:
1.多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2.需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3.对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
22).模板方法模式 (Template method):
原理:
使得子类可以不改变一个算法的结构即可以重定义该算法的某些特定步骤
换种说法:允许子类重载部分父类而不需要完全重写。
JDK中的此模式应用:
java.util.Collections#sort()
java.io.InputStream#skip()
java.io.InputStream#read()
java.util.AbstractList#indexOf()
应用场合:
1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
2.各子类中公共的行为应被提取出来并集中到一个公共类中以避免代码重复。
首先识别现有代码的不同之处,并且将不同之处分离为新的操作。
最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
3.控制子类的扩展
23).访问者模式 (Visitor):
原理:
作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.
JDK中的此模式应用:
javax.lang.model.element.Element 和javax.lang.model.element.ElementVisitor
javax.lang.model.type.TypeMirror 和javax.lang.model.type.TypeVisitor
应用场合:
1.一个对象结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2.需要对一个对象中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作‘污染’这些对象的类。
visitor使得你可以将相关的操作集中起来定义在一个类中。
当该对象结构被很多应用共享时,使用Visitor模式让每个应用包含需要用到的操作。
3.定义对象结构类很少改变,但经常需要在此结构上定义新的操作。
改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。
如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。