您的位置:首页 > 编程语言 > Java开发

Java之设计模式

2015-08-14 17:11 537 查看
《JAVA与模式》http://www.cnblogs.com/java-my-life/default.html?page=1
JDK中的设计模式http://blog.csdn.net/name_110/article/category/911282
Java之美[从菜鸟到高手演变]之设计模式
http://blog.csdn.net/zhangerqing/article/details/8194653
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、
访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式
SOLID原则
单一职责原则(SRP)
单一职责原则(Single Responsibility Principle,SRP)指出,一个类发生变化的原因不应该超过一个
在类中的一切都与该单一目的有关,即内聚性。这并不是说类只应该含有一个方法或属性,
类中可以包括很多成员,只要它们与单一的职责有关
开闭原则(OCP)
开闭原则(Open-Closed Principle,OCP)指出:类应该对扩展开放但对修改关闭
“对扩展开放”指的是设计类时要考虑到新需求提出时类可以增加新的功能
“对修改关闭”指的是一旦一个类开发完成,除了改正bug就不再修改它
应用:通常来说可以通过依赖关系的抽象实现开闭原则,比如接口或抽象类而不是具体类。通过创建新的类实现接口来增加功能。
在项目中应用OCP原则可以限制代码的更改,一旦代码完成,测试和调试之后就很少再去更改。
这减少了给现有代码引入新bug的风险,增强软件的灵活性
里氏替换原则(LSP)
里氏替换原则(Liskov Substitution Principle,LSP)适用于继承层次结构,指出设计类时客户端依赖的父类可以被子类替代,而客户端无须了解这个变化
应用:一般来说,如果父类型的一个子类型做了一些父类型的客户没有预期的事情,那这就违反LSP。比如一个派生类抛出了父类没有抛出的异常,
或者派生类有些不能预期的副作用。基本上派生类永远不应该比父类做更少的事情
一个违反LSP的典型例子是Square类派生于Rectangle类。Square类总是假定宽度与高度相等。如果一个正方形对象用于期望一个
长方形的上下文中,可能会出现意外行为,因为一个正方形的宽高不能(或者说不应该)被独立修改。
解决这个问题并不容易:如果修改Square类的setter方法,使它们保持正方形不变(即保持宽高相等),那么这些方法将弱化(违反)
Rectangle类setter方法,在长方形中宽高可以单独修改
违反LSP导致不明确的行为。不明确的行为意味着它在开发过程中运行良好但在产品中出现问题,或者要花费几个星期调试每天只
出现一次的bug,或者不得不查阅数百兆日志找出什么地方发生错误
接口隔离原则(ISP)
接口隔离原则(Interface Segregation Principle)指出客户不应该被强迫依赖于他们不使用的接口。
当我们使用非内聚的接口时,ISP指导我们创建多个较小的内聚度高的接口。还是一个降低类之间的耦合度的意思。
依赖反转原则(DIP)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体
指出高层次模块不应该依赖于低层次模块;他们应该依赖于抽象。第二,抽象不应该依赖于细节;细节依赖于抽象
迪米特法则(最少知道原则,也被称做封锁信息原则:只跟朋友交流,朋友圈)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立
合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承
好莱坞原则
不要调用我,我会调用你的
注意区分Facade模式、Adapter模式、Bridge模式与Decorator模式。
Facade模式注重简化接口,Adapter模式注重转换接口,Bridge模式注重分离接口(抽象)与其实现,Decorator模式注重稳定接口的前提下为对象扩展功能
Facade模式介绍http://superseven.iteye.com/blog/1850187
外部与一个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式
为子系统中的一组接口提供一个统一接口, 方便客户端使用子系统,客户端也不必关心子系统的具体实现。
Facade模式定义了一个更高层的接口,使子系统更加容易使用
facade设计模式的适用情况:
1、为一个复杂子系统提供一个简单接口时,由于子系统往往因为不断演化而变得越来越复杂,但这种变化不应该影响到客户的调用,
此时使用 Facade 模式对外提供一个访问的接口;此外,还可以提供多个 Facade 类以实现不同的子系统的定制;
2、客户与抽象类的实现部分之间存在着很大的依赖性。用 Facade 模式将这个子系统与客户以及其他的子系统分离解耦,让客户通过
Facade 类来访问具体子系统,这样也能够保持各个子系统的独立性,即可重用;
3、构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅
通过 Facade 进行通讯,从而简化了它们之间的依赖关系
几点小结:
1). Facade 模式旨在对客户提供一个访问入口、接口,具体内部的 Subsystem 子系统,客户端调用时并不需要知道
子系统的详细,针对不同的客户端也可以实现多个Facade来满足不同需求。
2). 从客户程序的角度来看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,
从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Façade接口的变化。
3). Facade设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。Facade很多时候更是一种架构设计模式。
4). Facade设计模式并非一个集装箱,可以任意地放进任何多个对象。Facade模式中组件的内部应该是
“相互耦合关系比较大的一系列组件”,而不是一个简单的功能集合
Façade模式在Java API的应用
public class RequestFacade implements HttpServletRequest
《JAVA与模式》之门面模式http://www.cnblogs.com/java-my-life/archive/2012/05/02/2478101.html
门面模式在Tomcat中的使用
可以看到它们返回都是各自的一个门面类,那么这样做有什么好处呢?
Request对象中的很多方法都是内部组件之间相互交互时使用的,比如setComet、setRequestedSessionId等方法(这里就不一一列举了)。
这些方法并不对外部公开,但是又必须设置为public,因为还需要跟内部组件之间交互使用。
最好的解决方法就是通过使用一个Facade类,将与内部组件之间交互使用的方法屏蔽掉,只提供给外部程序感兴趣的方法。
如果不使用Facade类,直接传递的是Request对象和Response对象,那么熟悉容器内部运作的程序员可以分别把ServletRequest和
ServletResponse对象向下转换为Request和Response,并调用它们的公共方法。比如拥有Request对象,就可以调用setComet、
setRequestedSessionId等方法,这会危害安全性
JDK中使用Facade模式的类是java.lang.Class,javax.faces.webapp.FacesServlet
无论一个类被设计的如何复杂,如果只需要获取这个类的名称的话,那么只需要为这个对象生成一个Class对象,
然后调用相应的方法即可,成功地对客户端隐藏了很多实现细节,运用了Facade模式
工厂模式
普通工厂模式,多个工厂方法模式,静态工厂方法模式,抽象工厂模式(Abstract Factory)
JDK中使用Abstract factory模式
创建一组有关联的对象实例。这个模式在JDK中也是相当的常见,还有很多的framework例如Spring。我们很容易找到这样的实例。
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()
单例模式(Singleton)
Java:单例模式的七种写法
http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html
《JAVA与模式》之单例模式
http://www.cnblogs.com/java-my-life/archive/2012/03/31/2425631.html
在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。
(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程
只允许一个实例。在 Effective Java中建议使用Emun.
java.lang.Runtime#getRuntime()
java.awt.Toolkit#getDefaultToolkit()
java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
java.awt.Desktop#getDesktop()
原型模式(Prototype)
该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象
了解对象深、浅复制的概念:
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,
而浅复制不彻底
《JAVA与模式》之原型模式http://www.cnblogs.com/java-my-life/archive/2012/04/11/2439387.html
原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法
创建出更多同类型的对象。这就是选型模式的用意
原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过
原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,
而无须再去通过new来创建
原型模式有两种表现形式:(1)简单形式、(2)登记形式,这两种表现形式仅仅是原型模式的不同实现
看website的例子
JDK中的克隆方法,two 种方法
1). 利用序列化实现深度克隆
把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,
写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
在Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),
再从流里读回来(反序列化),便可以重建对象
public Object deepClone() throws IOException, ClassNotFoundException{
//将对象写到流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
2). 对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆
在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,
复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象
protected native Object clone() throws CloneNotSupportedException;
1). 要实现(覆盖Object)对象的clone(),必须实现cloneable接口,实际上clone()方法名是任何合法的方法名都可以,
只要在方法里调用了super.clone()方法
2). 另外这个方法是protected的,不同的包是不能用的。这就可以解释为什么我们不能显示地调用Object.clone()这个方法
Object o1 = new Object();
Object o2 = o1.clone(); //报错
原型模式的优点
原型模式允许在运行时动态改变具体的实现类型。原型模式可以在运行期间,由客户来注册符合原型接口的实现类型,也可以
动态地改变具体的实现类型,看起来接口没有任何变化,但其实运行的已经是另外一个类实例了。
因为克隆一个原型就类似于实例化一个类。
原型模式的缺点
原型模式最主要的缺点是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类
来说不是很难,而对于已经有的类不一定很容易,特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候


简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别

/article/4835569.html
http://www.cnblogs.com/java-my-life/archive/2012/03/22/2412308.html http://www.cnblogs.com/java-my-life/archive/2012/03/25/2416227.html http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
工厂方法模式和简单工厂模式

  工厂方法模式和简单工厂模式在结构上的不同很明显。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。

  工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么不妨把抽象工厂类合并到

具体工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改为静态方法,这时候就得到了简单工厂模式

抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构


《JAVA与模式》之模板方法模式

使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。HttpService类提供了一个service()方法,

这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,

因此这是典型的模板方法模式

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: