常见设计模式简述

设计模式

Java 模式

23中模式

1.单例模式

1.私有的构造方法->防止其他类调用,只能本类调用

2.定义private,静态的一个实例对象属性

3.public,静态的,方法要加synchronized同步的方法——>防止在方法里创建对象时间过长,

其他的类也来调用方法创建对象,这样就创建了几个对象,不符合单列

4.方法里判断对象是否为空(null),为空new一个新的对象,否则直接返回对象

2.简单工厂

隐藏了类的实现,不知道他有多少个子类实现,工厂里返回的不知道是哪个实现类

简单工厂模式的意图。

如果用面向对象的思想来理解的话,营业员在这里就充当了一个工厂的角色,他负责根据你的请求返回你需要的食品对象。

3.策略模式(Strategy)

定义:定义一系列的算法,把它们一个个封装起来, 并且使它们可根据不同应用需求,相互替换。

本模式使得算法可独立于使用它的客户而变化。

解决问题:某个具体的解决方法有很多种可选择的实现。

常用地方:以不同的格式保存文件,以不同的算法压缩文件;

以不同的格式输出同样数据的图形,比如曲线 或框图bar等

当保存图片的时候,有gif,pmp,jpg,

4.模板模式(Template)

定义:定义一个操作中 算法的骨架,子类根据不同实际细节,各自实现

父类定义一些流程,子类来实现。

通俗点的理解就是 :完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成

解决问题:重要是解决子类之间代码或者是流程的重复问题。

常用地方:DAO 模式里面的模板类,Spring里面的常用模板,比如:JdbcTemplate

实例说明

来举个例子: 比如我们做菜可以分为三个步骤 (1)备料 (2)具体做菜 (3)盛菜端给客人享用,这三部就是算法的骨架 ;

然而做不同菜需要的料,做的方法,以及如何盛装给客人享用都是不同的这个就是不同的实现细节。

优点

 (1)具体细节步骤实现定义在子类中,子类定义详细处理算法是不会改变算法整体结构。

 (2)代码复用的基本技术,在数据库设计中尤为重要。

 (3)存在一种反向的控制结构,通过一个父类调用其子类的操作,通过子类对父类进行扩展增加新的行为,符合“开闭原则”。

不足

每个不同的实现都需要定义一个子类,会导致类的个数增加,系统更加庞大。

5.观察者模式

定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

解决问题:解决多个对象间相互依赖关系的相互通知。

使用:当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

例子:马路的红灯,当红灯亮的时候,汽车,小轿车,大卡车,都要停住

有一名店(Shop),为了财物安全起见,除了在店内装了摄像头(Camera)来监控店内的总人数外,还聘请了一些门卫(Camera)守在店门口,对来访的客人进行实名[shi ming]登记,即客人进入时要记名,客人出店时也要记录其离去。

6.组合模式(Composite)

定义:将对像以树形结构组织起来,以达成部分-整体的层次结构,

使得客户端对单个对象和组合对象的使用具有一致性.

解决问题:树形数据结构的方案

文件系统由目录和文件组成。每个目录都可以装内容。

目录的内容可以是文件,也可以是目录。按照这种方式,

计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,

那么你可以使用组合模式Composite。

生活中的例子:

Composite模式结构图(内图)

7.命令模式(Command)

定义: 将来自客户端的请求传入一个对象,无需了解这个请求激活的

动作或有关接受这个请求的处理细节。

解决问题:只关心行为,不关心具体执行类或者实现.

一般的Command模式都是针对图形界面的 ,它实际就是菜单命令,我们

在一个下拉菜单选择一 个命令时,然后会执行一些动作。

当地政府下达一个命令,需要对某个村进行培训,需要这个村里的每个人知道,

但政府,不需要对那个村的所有去说,他只要把这件事情,

告诉村长,由村长通过一定的形式去说,最后,政府只要知道,这个村里的

每个人知道就可以了,政府不需要知道,这个村里的人是这么知道的,

可能村长自己一个个去告诉村民的,可能村长告诉几个人,这些人一个个

的传下去的,这些他都不需要知道,

8.外观模式(门面模式(Facade)

客户程序经常会与复杂系统的内部子系统之间产生耦合,

而导致客户程序随着子系统的变化而变化。

定义:为子系统中的一组接口提供一个一致的界面

这个接口使得这一子系统更加容易使用。

生活中的例子

外观模式为子系统中的接口定义了一个统一的更高层次的界面,以便于使用。

当消费者按照目录采购时,则体现了一个外观模式。——消费者拨打一个号码

与客服代表联系,客服代表则扮演了这个"外观",他包含了与订货部、收

银部和送货部的接口。(消费者不需要管理什么,直接拿东西就可以了。)

9.装饰器模式(Decorator)

定义:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

解决问题:一个对象需要经常动态增加属性或职责

生活中的例子

不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。

在项目中使用:项目中打印的报表

项目: 观察者模式,组合模式,命令模式,模板模式

细的流程

JUnit用到了比较多的设计模式

首先创建一个观察者模式里的Subject(主题)也就是TestResult类,

在这个类里有个集合,用来装观察者的,也就这里面的监听器(TestListenerTextImpl类),当然可以装其他的监听器类,但都要实现监听器TestListener接口,

接下来,加一个监听器进去,到TestResult类里集合里去,现在使用的是文本监听器,还有其他的监听器,如:单元测试里的,红条,和绿条,代表错误,在控制台打印。

接下来创建一个Test,他是通过他的子类来创建的,里面要传一个测试类进去,(SimpleTest.Class)首先判断传入的测试类是不是Test的子类,是他的子类,在往下执行,否则给于警告,他还会去判断,传入的测试类里面的方法,是不是标准的单元测试方法

1没有参数 2 test开头 3返回值为void ,这些他都要进行判断,

然后他会生成一个构造器(Constructor),通过构造器创建一个实例,

然后他会重复的while循环判断superClass是不是Test的子类,不是

跳出循环,然后通过命令模式,调用Test里面的run方法,因为这个是组合模式,

首先执行TestSuite里run方法,他会自动循环执行,叶子里面的run方法,也就是TestCase里的run方法,在这个方法里,又调用了观察者模式TestResult类里的run方法,这时候就是监听器开始监听了,也就是观察者,开始行动了。

在JUnit里面就是相应的setUp和tearDown方法。如果没有这两个方法,那么我们要在每个测试方法的代码内写上一大堆重复的初始化和清理代码,这是多么愚蠢的做法。那么JUnit是怎么让setUp和tearDown在测试执行前后被调用的呢? 如果你查看下TestCase方法,你会发现TestCase和TestSuite的run()方法都是将执行测试的任务委托给了TestResult,由TestResult去执行测试代码并收集测试过程中的信息(这里用到了Collecting Parameter模式)。

组合

1)JUnit可以统一地处理组合结构TestSuite和单个对象TestCase,避免了条件判断,并且可以递归产生更复杂的测试对象
2)很容易增加新的TestCase。

观察者模式-

1)上面提到的Subject与Observer的抽象耦合,使JUnit可以支持不同的使用方式
2)支持了广播通信,目标对象不关心有多少对象对自己注册,它只是通知注册的观察者

模板

1)模板方法是代码复用的基本技术,在类库中经常使用,可以减少大量的代码重复
2)通过隔离算法的不变和可变部分,增加了系统的灵活性,扩展算法的某些步骤将变的很容易。

runBare方法是模板模式

http://www.blogjava.net/killme2008/archive/2007/04/05/108702.html

http://www.blogjava.net/killme2008/archive/2007/04/05/108743.html

http://www.blogjava.net/killme2008/archive/2007/04/06/108860.html

http://www.vipcn.com/chengxukaifa/Java/328560_9.html

Junit源代码

JUnit源代码中用到了比较多的设计模式,先说下用到了那些模式,

观察者模式,组合模式,命令模式,模板模式。

说下观察者模式,

在这里面TestResult类就是Subject(主题),

而这里的观察者就是监听器,使用观察者模式使JUnit可以支持不同的使用方式

比如:我可以在加一个监听器,这个可能以红条,绿条,方式,来显示正确,错误信息

还有,目标对象不关心有多少对象对自己注册,它只是通知注册的观察者

下面说下组合模式:

TestSuite相当于树枝,TestCase相当于叶子,在这个上面,增加一个东西,

删除一个东西,不需要动他的源代码,加一个类就可以了,使用组合模式使

JUnit可以统一地处理组合结构TestSuite和单个对象TestCase,避免了条件判断,并且可以递归产生更复杂的测试对象,而且很容易增加新的TestCase。

命令模式:

通过Test直接调用一个(run())方法,就可以把我们所需要的的事情,执行完成,

我们不需要管他里面是这么实现的,是通过那些类来实现的,

所以这就是命令模式,简化用户操作。

模板模式:

在TestCase类里,在一个方法里定义流程,使用setUp和tearDown方法

他的子类可以去实现这些方法,所以这就是模板模式。

如果这里没使用模板模式的话,就要在JUnit里的,每个测试方法的代码内写上一大堆重复的初始化和清理代码,使用模板模式,只要在前后调用setUp和tearDown方法,就可以,

增加了系统的灵活性,扩展算法的某些步骤将变的很容,并且减小了很多的重覆代码。

面试Junit——3.8源代码

Junit——3.8源代码是由四人帮(GoF)其中之一人写的,也是设计模式的创始人(先驱四人),

所以他在Junit——3.8源代码里使用了很多的设计模式,下面讲下流程:

首先创建一个TestResult对象,然后,把监听器加进去,在这里,源代码里使用了一个文本监听器,他主要在控制台打印信息,我们也可以加另外一个监听器进去,这个可能以红条,绿条,的方式来显示正确,错误信息,在我们eclipse里面单元测试就是以这种方式显示正确,错误信息,在这里体现了对象间一对多的依赖关系(TestResult——》多个监听器),所以这里使用了观察者模式。好处:使JUnit可以支持不同的使用方式。

接下来创建一个Test,是通过TestSuite子类来创建的,里面传一个被测试类进去,

这里使用了组合模式,解决了树形结构方案,当我测试的时候,只要调用根部的(顶级接口)

方法,他会自动执行树枝(TestSuite),树叶(TestCase),里面的测试方法,不需要,每个类都去调用,所以,这是他的好处。

再是执行run方法,执行这个方法,里面肯定执行了一些流程,写了一些,复查的

业务程序代码,可我们不需要管这些,调用run方法,结果出来了,所以

这里体现了命令模式。

TestCase里一个方法里,写了一些流程,调用了setUptearDown方法,

这两个方法,由他子类复写的,所以这里使用了模板模式,(父类定义流程,子类实现)

模板模式使用在这里肯定有他的好处,我说下他的好处:如果这里没使用模板模式的话,

就要在JUnit里的,每个测试方法的代码内写上一大堆重复的初始化和清理代码,这样

可读性不高,而且还有很多代码重复,写起来也很繁琐。

使用模板模式以后,只要在前后调用setUp和tearDown方法,就可以了,

使用也更加方便,并且减小了很多的重覆代码。

10.状态模式

定义: 不同的状态,不同的行为;或者,每个状态有着相应的行为.

何时使用?
State模式在实际使用中比较多,适合"状态的切换". 因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了.

状态模式优点:
(1) 封装转换过程,也就是转换规则
(2) 枚举可能的状态,因此,需要事先确定状态种类。

生活中的列子:

QQ啊大家都知道,他有在线,隐身,离线,很多种,

在不同的状态,可做的事情不同,

我们打篮球的时候运动员可以有正常状态,不正常状态,和超常状态

11.职责链模式

定义:为了避免请求的发送者和接收者之间的耦合关系,组织处理复杂的业务流程。

使多个接受对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

解决问题

1 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。

2 你想在不明确指定接受者的情况下,向多个对象中的一个提交一个请求。

3 可处理一个请求的对象集合应该被动态指定。

职责链的好处:每个对象只需要保持一个指向其后继者的引用,而不需要保持所有候选接收者的引用;降低了耦合度。我们可以随时增加或修改一个请求的结构,增强给对象指派职责的灵活性。

生活中的例子:

举一个申冤例子。假设你有个冤情。最先找到村委会,如果这个请求属于其职责范围之内并且可以得到圆满解决,那么申冤到此结束,否则会被传递到镇政府。同理如果这个请求在其职责范围并且可以给你满意的答复,申冤到此结束,否则再到市政府。依次类推,可能一直到中央。这就所谓的“到京城告御状”。

机械硬币分栋银行,这里并不是每个硬币都分一个滑槽,而且使用的是一个滑槽,

当硬币落下时,硬币被银行内部的机械导向至接收盒。

12.抽象工厂模式

定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

生活中的例子

抽象工厂的目的是要提供一个创建一系列相关或相互依赖对象的接口,而不需要指定它们具体的类。这种模式可以汽车制造厂所使用的金属冲压设备中找到。这种冲压设备可以制造汽车车身部件。同样的机械用于冲压不同的车型的右边车门、左边车门、右前挡泥板、左前挡泥板和引擎罩等等。通过使用转轮来改变冲压盘,这个机械产生的具体类可以在三分钟内改变。

13.适配器模式

定义:将一个类的接口转换成客户希望的另外一个接口。使原本由于接口不兼容而能一起工作的类可以一起工作。

解决问题:已经存在类似功能的类或接口,但是方法签名不一样。

分两种:类适配器,对象适配器

区别:类适配器是以“多继承”耦合度高,对象适配器以“多组合”耦合度低。

(尽量用对象适配器,多用合成/聚合、少用继承)

生活中的例子

例如:中国的电源电压为 220V ,而日本的电源电压 110V ,在国内使用日本原装电器时,就必须有一个电源适配器将 220V 的电压适配至 110V 。

新的电脑机箱一般都是 USB 接口,而旧的电脑机箱上根本就没有 USB 接口,而只有一个 PS2 接口,这时就必须有一个 PS2 转 USB 的适配器,将 PS2 接口适配为 USB 接口。

一般家庭中电源插座有的是两个孔(两项式)的,也有三个孔(三项式)的。很多时候我们可能更多地使用三个引脚的插头,但是那种两孔的插座就不能满足我们 的需求,此时我们一般会买一个拖线板,该拖线板的插头是是两脚插头,这样就可以插入原先的两孔插座,同时拖线板上带有很多两孔、三孔的插座!这样不仅可以 扩容,更主要的是将两孔的插座转变为三孔的插座。

14.建造模式(Builder )

目的:其意图是将一个复杂对象的构建与他的表示分离,使得同样的构建创建过程可以创建不同的表示。

适用性:

1. 当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式时

2. 当构造过程必须允许被构造的对象有不同的表示时。

(儿童餐店)

意图

将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

生活中的例子

典型的儿童 餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。无论顾客点的是汉堡,三名治还是鸡肉,过程都是一样的。柜台的员工直接把主食 ,辅食和玩具放在一起。这些是放在一个袋子中的。饮料被倒入杯中,放在袋子外 边。这些过程在相互竞争的餐馆中是同样的

15.代理模式 (Proxy)

意图:为其他对象提供一种代理以控制对这个对象的访问。

生活中的例子;

比如在网络异地,有一个专门的服务器用于提供专业的天气预报的相关信息,我们在网络的其它地方需要获取我们感兴趣的城市的天气预报,为此,我们需要在客户端本地创建一个代理类,由它来与异地的天气预报服务器上的相关服务进行交互,并按照定制的接口对本地开放,我们通过这些接口所开放的服务来获取我们想要的相关信息。

16.中介者模式 (Proxy)

定义:用一个中介对象来封装一系列的对象交互。

中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互 简单点来说,将原来两个直接引用或者依赖的对象拆开,在中间加入一个“中介”对象,使得两头的对象分别和“中介”对象引用或者依赖。

生活中的例子:

适用性:
1.一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
2.一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
3.想定制一个分布在多个类中的行为,而又不想生成太多的子类。

//拿一个男人和女人通过媒人约会的例子来实现这种设计模式...:)哈哈.这就是“通俗模式“

媒人就是中介者。

在Java世界中,Button按钮和监听者之间通过Frame进行协作,Frame就类是一个中介者。

原则

1.单一职责原则
一个类,最好只做一件事,只有只有一个引起它变化的原因。

所谓职责,我们可以理解他为功能,就是设计的这个类功能应该只有一个,而不是两个或更多。也可以理解为引用变化的原因,当你发现有两个变化会要求我们修改这个类,那么你就要考虑撤分这个类了。因为职责是变化的一个轴线,当需求变化时,该变化会反映类的职责的变化。
单一职责原则可以看作是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。职责过多,可能引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而极大的损伤其内聚性和耦合度。单一职责,通常意味着单一的功能,因此不要为类实现过多的功能点,以保证实体只有一个引起它变化的原因。

2.开闭原则

简单地说就是对扩展性应当是开放的,对与修改性应当是关闭的。
依据这个原则,我们在设计的时候,就要考虑设计中什么会发生变化,并且不让这变化影响到设计,当然在这里就会遇到“过度设计”的问题了,而且预测变化对经验的要求比较高,创建抽象所付出的代价也很大,所以只能限定在可能的变化上,仅仅对程序中呈现出频繁变化的部分进行抽象。
至少应当做到的是:一种可变性不应当散落在代码的很多角落里,而应当被封装在一个对象里面,更不应该和另外一种可变性混在一起。

在软件领域:需求总是变化世界上没有一个软件是不变的

就很好的体现了这个。

3. Liskov替换原则

子类必须能够替换掉它们的父类。

另外还有一句话就是:子类具有扩展父类的责任,而不是重写的责任。

4. 依赖倒置原则

高层模块不应该依赖于低层模块。二者都应该依赖于抽象。

抽象不应该依赖于细节,细节应该依赖于抽象。

抽象层次包含的是应用系统的商务逻辑和宏观的战略性决定,而具体层次含有的是和实现有关的算法与逻辑,具体层次的代码会经常发生变动,不能避免出现错误。所以便应该是高层的策略设置模块影响低层的细节实现模块,而不是相反。比如说,先制定业务逻辑的规则,再实现数据库操作等等细节。

比较合适的模型是:每个较高的层次都为它需要的服务声明一个抽象接口,较低的层次实现这个接口,每个高层类都通过该抽象接口使用下一层。换句话来说,由客户类声明它们需要的服务接口,仅当客户需要时才对接口进行改变,所以改变实现细节的类就不会影响到客户。

5. 接口隔离原则

不应该强迫客户依赖于他们不用的方法。

使用多个专门的接口比使用单一的总接口要好,一个类对另外一个类的依赖性应当建立在最小的接口上。

6.迪米特法则

就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。

门面模式就是使用了这个。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值