面向对象的设计模式学习.docx
- 文档编号:7570865
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:30
- 大小:496.93KB
面向对象的设计模式学习.docx
《面向对象的设计模式学习.docx》由会员分享,可在线阅读,更多相关《面向对象的设计模式学习.docx(30页珍藏版)》请在冰豆网上搜索。
面向对象的设计模式学习
23种设计模式可以在功能设计,功能的编程实现设计,程序结构优化和性能优化等方面给我们以帮助。
大部分模式我们在编程的过程中都已经无意识的使用过。
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。
这是面向对象编程人员必须掌握的一门内功。
设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案。
面向对象设计模式描述了面向对象设计过程中、特定场景下、类与相互通信的对象之间常见的组织关系。
整个设计模式贯穿一个原理:
面对接口编程,而不是面对实现.目标原则是:
降低耦合,增强灵活性.
1.1.创建型
创建型:
负责对象创建。
1、Singleton,单例模式:
定义:
保证一个类只有一个实例,并提供一个访问它的全局访问点。
单例模式有延迟初始化和非延迟两种实现方式。
单体模式注意事项:
有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。
Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java的类线程内存等概念有相当的了解。
总之:
如果你的应用基于容器,那么Singleton模式少用或者不用,可以使用相关替代技术。
二、AbstractFactory,抽象工厂模式
又称为工具箱,产生产品族,但不利于产生新的产品。
定义:
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
面向对象的设计中,我们使用“new”的方式来创建对象,这样的问题就是:
我们依赖实现,不能应对“具体实例化类型”的变化。
变化点在“对象创建”,因此就封装“对象创建”,
面向接口编程——依赖接口,而非依赖实现。
AbstractFactory模式的几个要点
1.如果没有应对“多系列对象创建”的需求变化,则没有必要使用AbstractFactory模式,这时候使用简单的静态工厂完全可以。
2."系列对象"指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
3.AbstractFactory模式主要在于应对“新系列”的需求变动。
其缺点在于难以应对“新对象”的需求变动。
4.AbstractFactory模式经常和FactoryMethod模式共同组合来应对“对象创建”的需求变化。
(FactoryMethod是应对对象的变化,)
Builder模式和AbstractFactory模式的区别
Builder模式更强调的是对象部分的“构建”这样一个严格的过程,它构建的是整个对象的各个部分。
它把构建稳定下来之后,各个部分在变化,最后组合成一个整体的对象。
AbstractFactory模式构建的是一组系列交互的对象。
互相依赖、互相交互的对象和一个对象的各个部分是有区别的。
三、FactoryMethod,工厂方法模式
又称为多形性工厂;
定义:
一个用于创建对象的接口,让子类决定实例化哪一个类,FactoryMethod使一个类的实例化延迟到了子类。
1)抽象工厂角色(AbstractCreator):
这是工厂方法模式的核心,它与应用程序无关。
是具体工厂角色必须实现的接口或者必须继承的父类。
在java中它由抽象类或者接口来实现。
2)具体工厂角色(Creator):
它含有和具体业务逻辑有关的代码。
由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色(AbstractProduct):
它是具体产品继承的父类或者是实现的接口。
在java中一般有抽象类或者接口来实现。
4)具体产品角色(Product):
具体工厂角色所创建的对象就是此角色的实例。
在java中由具体的类来实现。
四、Builder,建造模式
建造模式,又叫生成器模式。
定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
Builder模式主要用于“分步骤构建一个复杂的对象”。
在这其中“分步骤”是一个稳定的算法(即Director),而复杂对象的各个部分(即ConcreteBuilder)则经常变化。
变化点在哪里,封装哪里——Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。
其缺点在于难以应对“分步骤构建算法”的需求变动。
(例如房屋构造如果经常改变,那么这个Builder模式也没有意义了)
AbstractFactory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。
Builder模式通常和Composite模式组合使用。
应用举例:
数据库连接池(每一个连接的重用)
五、Prototype,原始模型模式
定义:
用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。
原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。
缺点是每一个类都必须配备一个克隆方法。
在Java中Prototype模式变成clone()方法的使用,由于Java的纯洁的面向对象特性,使得在Java中使用设计模式变得很自然,两者已经几乎是浑然一体了。
这反映在很多模式上,如Interator遍历模式。
1.2.行为型
行为型:
类与对象交互中的职责分配。
六、Iterator,迭代器模式:
迭代器模式,又叫游标模式,
定义:
提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
这个模式已经被整合入Java的Collection.在大多数场合下无需自己制造一个Iterator,只要将对象装入Collection中,直接使用Iterator进行对象遍历
1)迭代器角色(Iterator):
迭代器角色负责定义访问和遍历元素的接口。
(Iterator)
2)具体迭代器角色(ConcreteIterator):
具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
3)容器角色(Container):
容器角色负责提供创建具体迭代器角色的接口。
4)具体容器角色(ConcreteContainer):
具体容器角色实现创建具体迭代器角色的接口。
多个对象聚在一起形成的总体称之为聚合,聚合对象是能够包容一组对象的容器对象。
迭代模式将迭代逻辑封装到一个独立的子对象中,从而与聚合本身隔开。
迭代子模式简化了聚合的界面。
每一个聚合对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。
迭代算法可以独立于聚合角色变化。
七、Observer,观察者模式:
定义:
定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
观察者模式定义了一种一队多的依赖关系,让多个观察者对象(observerObject)同时监听某一个主题对象(subjectObject)。
这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
应用举例:
电子商务中,商品的变化,通知关注的用户。
Java的API还为为我们提供现成的Observer接口Java.util.Observer,
八、TemplateMethod,模板方法模式
定义:
定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中.TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
介绍:
变化——是软件设计的永恒主题,如何管理变化带来的复杂性?
设计模式的艺术性和复杂度就在于如何分析,并发现系统中的变化点和稳定点,并使用特定的设计方法来应对这种变化.
如果你只想掌握一种设计模式,那么它就是TemplateMethod!
TemplateMethod模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。
它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展,是代码复用方面的基本实现结构。
模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造方法的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。
不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。
先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。
应用举例:
九、Command,命令模式:
定义:
将一个请求封装为一个对象,从而使你可用不同的请求对客户(客户程序,也是行为的请求者)进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
Command:
定义命令的接口,声明执行的方法。
ConcreteCommand:
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
接收者,真正执行命令的对象。
任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。
这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
创建具体的命令对象,并且设置命令对象的接收者。
注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
命令模式把一个请求或者操作封装到一个对象中。
命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。
命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。
系统支持命令的撤消。
命令模式解决的问题:
在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。
但在某些场合——比如需要对行为进行“记录、撤销/重做(undo/redo)、事务”等处理,这种无法抵御变化的紧耦合是不合适的。
在这种情况下,如何将“行为请求者”与“行为实现者”解耦?
将一组行为抽象为对象,可以实现二者之间的松耦合。
命令模式的要点:
Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”。
实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能会保存一些额外的状态信息。
通过使用Composite模式,可以将多个“命令”封装为一个“复合命令”MacroCommand。
应用举例:
调度服务器,activeMQ服务器,监测点客户端。
十、State,状态模式:
定义:
不同的状态,不同的行为;或者说,每个状态有着相应的行为。
Ø状态改变引起行为改变
状态模式允许一个对象在其内部状态改变的时候改变行为,这个对象看上去象是改变了它的类一样。
状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。
1)使用环境(Context)角色:
客户程序是通过它来满足自己的需求。
它定义了客户程序需要的接口;并且维护一个具体状态角色的实例,这个实例来决定当前的状态。
2)状态(State)角色:
定义一个接口以封装与使用环境角色的一个特定状态以及和这个特定状态相关的行为。
3)具体状态(ConcreteState)角色:
实现状态角色定义的接口。
类图,结构非常简单也与策略模式非常相似。
状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。
当系统的状态变化时,系统便改变所选的子类。
应用举例:
hibernate的对象持久化,登录用户锁定,PS中工具箱等。
优缺点:
1) 优点:
避免了为判断状态而产生的巨大的if或case语句。
将对象行为交给状态类维护后,对于上层程序而言,仅需要维护状态之间的转换规则。
2) 会导致某些系统有过多的具体状态类。
适用性
1) 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2) 一个对象含有庞大的条件分支语句,这些分支依赖于它的状态。
这个状态通常用一个或多个枚举常量表示。
通常有多个操作包含这一相同的结构。
State模式将每一个分支放入一个独立的类中。
这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
十一、Strategy,策略模式:
定义:
定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,此模式使得算法可以独立于使用它们的客户。
Strategy及其子类为组件提供了一系列可重用的算法
策略模式针对一组算法,将每一个算法封装(封装性)到具有共同接口的独立的类中,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换,使得算法可以在不影响到客户端的情况下发生变化(透明性)。
算法与对象本身解耦
策略模式把行为和环境分开。
环境类负责维持和查询行为类,各种算法在具体的策略类中提供。
由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。
Strategy类型里面不携带状态信息
Strategy类型里面不携带状态信息(这是与模板方法的区别,模板方法本身是携带状态信息的),我们不能把它看成一种实例,即使有状态,也是会通过参数传入。
Strategy是独立的
一个Strategy定义了一个算法的完整步骤和结构,只要用一个Strategy具体类,就可以完成整个算法的操作,不会有其它依赖和耦合。
Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。
含有许多条件判断语句的代码通常都需要Strategy模式。
与State类似,如果Strategy对象没有实例变量,那么各个上下文可以共享一个Strategy对象,从而节省对象开销。
Strategy模式适用的是算法结构中整个算法的改变,而不是算法中某个部分的改变。
策略模式和模版模式的区别:
1)策略模式针对的是一个整个算法改变。
模版模式针对的是算法中某个或某几个部分的改变。
2)策略模式是把行为和环境分开;而模版模式是把行为和行为实现延迟。
应用举例:
以不同的格式保存文件,以不同的算法压缩文件,截取不同形状的图片等。
十二、ChinaofResponsibility,职责链模式:
定义:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
请求在这个链上传递,直到链上的某一个对象决定处理此请求。
客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。
一个请求可能有多个接受者,但是最后真正的接受者只有一个。
一个请求可以最终不被任何接收端对象所接受。
处理者有两个选择:
承担责任或者把责任推给下家。
纯的责任链模式:
规定一个具体处理者角色只能对请求作出两种动作:
自己处理;传给下家。
不能出现处理了一部分,把剩下的传给了下家的情况。
而且请求在责任链中必须被处理,而不能出现无果而终的结局。
责任链的“链”只是为了说明一种传递的思想,在实现的过程中实际可以直线,树状,环状等。
责任链模式优缺点:
降低了耦合、提高了灵活性。
但是责任链模式可能会带来一些额外的性能损耗,因为它每次执行请求都要从链子开头开始遍历。
责任链的维护:
组建责任连接,这里我们自己维护。
以参考使用list或者map来进行注册。
可以使用spring来管理具体处理者角色的引入。
当有了新的处理者需要添加的时候,仅仅需要修改下配置文件。
应用举例:
处理UI的消息
古代:
《墨子.迎敌祠》里描守城军队的结构:
“城上步一甲、一戟,其赞三人。
五步有伍长,十步有什长,百步有佰长,旁有大帅,中有大将,皆有司吏卒长。
”
十三、Mediator,中介者模式
中介者模式又叫调停者模式。
定义:
用一个中介对象来封装一系列关于对象交互行为.
中介者使各个对象不需要显示地相互引用,从而使其耦合性松散,而且可以独立地改变他们之间的交互。
用一个中介对象来封装一系列的对象交互。
中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。
保证这些作用可以彼此独立的变化。
调停者模式将多对多的相互作用转化为一对多的相互作用。
调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。
应用:
在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断地变化。
在这种情况下,我们可使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好地抵御变化。
应用举例:
聊天室程序。
随着控制逻辑的复杂化,Mediator具体对象的实现可能相当复杂。
这时候可以对Mediator对象进行分解处理。
十四、Visitor,访问者模式:
定义:
作用于某个对象群中各个对象的操作.它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.
简单的说,就是对象不变,作用于对象的操作变化时,可采用该模式。
使用Visitor模式的前提:
使用访问者模式是对象群结构中(Collection)中的对象类型很少改变。
在两个接口Visitor(访问者)和Visitable(可访者)中,确保Visitable很少变化,也就是说,确保不能老有新的Element元素类型加进来,可以变化的是访问者行为或操作,
当需要添加新的操作的时候,只需要添加一个Visitor实现类即可。
这种结构把扩展操作所带来的改变转嫁给了Visitor的子类。
不但Visitor实现要变化,Visistable也要增加相应行为,GOF建议是,不如在这些对象类中直接逐个定义操作,无需使用访问者设计模式(但在java中,可结合使用java的反射机制解决这种情况)。
应用举例:
各大互联网服务商提出的所谓的应用开放平台,跟这种思路相似。
十五、Interpreter,解释器模式:
定义:
给定一个语言,定义它的文法的一种表示,并提供一个解释器,来解释该语言中的句子。
给定一个语言后,可以定义出其文法的一种表示,并同时提供一个解释器。
客户端可以使用这个解释器来解释这个语言中的句子。
解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。
在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。
在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。
每一个命令对象都有一个解释方法,代表对命令对象的解释。
命令对象的等级结构中的对象的任何排列组合都是一个语言。
应用举例:
把阿拉伯数字变成中文数字,把日期变成农历的日期,Quartz表达式的解释,正则表达式,sql语句等。
气象局数据判断分析项目:
用到数据过滤器。
("T50000:
60000orT70000:
80000orT90000:
95000orT100000:
180000")。
十六、Memento,备忘录模式:
定义:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
这样以后就可将该对象恢复到原先保存的状态。
备忘录对象(Memento对象)是一个用来存储另外一个对象内部状态的快照的对象。
缺点:
Memento模式的缺点是耗费大,如果内部状态很多,再保存一份,无意要浪费大量内存.
应用举例:
JSP+JavaBean开发中,表单信息的记录。
1.3.结构型
结构型:
处理类与对象间的组合。
十七、Composite,组合模式:
组合模式又叫合成模式。
定义:
将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性.
合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。
Composite使得用户对单个对象和组合对象的使用具有一致性。
合成模式就是一个处理对象的树结构的模式。
合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。
看下组合模式的组成。
1)抽象构件角色(Component):
它为组合中的对象声明接口,也可以为共有接口实现缺省行为。
2)树叶构件角色(Leaf):
在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。
3)树枝构件角色(Composite):
在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。
组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等操作。
但是管理方法是在Component中就声明还是在Composite中声明呢?
一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化。
目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。
但树叶是不存在子类的,因此Component声明的一些方法对于树
叶来说是不适用的。
这样也就带来了一些安全性问题。
另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法。
这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。
《设计模式》一书认为:
在这一模式中,相对于安全性,我们比较强调透明性。
对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。
十八、Facade,外观模式:
外观模式又叫门面模式。
定义:
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
直接访问模式。
外观模式
外观模式减少了客户程序和子系统之间的耦合,增加了可维护性.
外观模式有3个角色(门面角色,子系统角色,客户端角色)。
1)门面角色(facade):
这是门面模式的核心。
它被客户角色调用,因此它熟悉子系统的
功能。
它内部根据客户角色已有的需求预定了几种功能组合。
2)子系统角色:
实现了子系统的功能。
对它而言,facade角色就和客户角色一样是未知的,
它没有任何facade角色的信息和链接。
3)客户角色:
调用facade角色来完成要得到的功能。
外部与一个子系统的通信必须通过一个统一的门面对象进行。
门面模式提供一个高层次的接口,使得子系统更易于使用。
每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。
但整个系统可以有多个门面类。
要点:
1.外观模式为复杂子系统提供了一个简单接口,并不为子系统添加新的功能和行为。
2.外观模式实现了子系统与客户之间的松耦合关系。
3.外观模式没有封装子系统的类,只是提供了简单的接口。
如果应用需要,它并不限制客户使用子系统类。
因此可以在系统易用性与通用性之间选择。
4.外观模式注重的是简化接口,它更多的时候是从架构的层次去看整个系统,而并非单个类的
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 面向 对象 设计 模式 学习