《面向对象的软件工程PPT.ppt》由会员分享,可在线阅读,更多相关《面向对象的软件工程PPT.ppt(79页珍藏版)》请在三一办公上搜索。
1、面向对象的软件工程,第1章 面向对象的概念和原则,1.2 面向对象的概念,消息消息是指对象间相互联系和相互作用的方式。一个消息主要由5部分组成:发送消息的对象、接收消息的对象、消息传递办法、消息内容(参数)、反馈。,4.9 模式编程介绍,程序设计是思维具体化的一种方式,是思考如何解决问题的过程,设计模式是在解决问题的过程中,一些良好思路的经验集成,最早讲设计模式,人们总会提到 Gof 的著作,它最早将经典的 23 种模式集合在一起说明,对后期学习程序设计,尤其是对从事对象导向程序设计的人们起了莫大的影响。面向对象的设计模式主要有三种:创建(Creational)模式。结构(Structural
2、)模式。行为(Behavioral)模式。,4.9 模式编程介绍,创建(Creational)模式对象的产生需要消耗系统资源,所以如何有效率的产生、管理与操作对象,一直都是值得讨论的课题,Creational 模式即与对象的建立相关,在这个分类下的模式给出了一些指导原则及设计的方向。在这里主要介绍创建(Creational)模式中的:单态(Singleton)模式简单工厂(Simple Factory)模式,4.9 模式编程介绍,单态(Singleton)模式动机在软件系统中,经常有这样一些特殊的类,必须保证它在整个系统中只存在一个实例,才能确保它们的逻辑正确性以及良好的效率。如何绕过常规的构
3、造器,提供一种机制来保证一个类只有一个实例?这应该是类设计者的责任,而不是使用者的责任!,4.9 模式编程介绍,单态(Singleton)模式意图保证一个类仅有一个实例,并提供一个该实例的全局访问点。设计模式GoF,4.9 模式编程介绍,单态(Singleton)模式单态(Singleton)模式的UML结构类图如下:,4.9 模式编程介绍,单态(Singleton)模式单态(Singleton)模式的几个要点:Singleton模式中的实例构造器可以根据需要设计成protected以允许子类派生。Singleton模式只考虑到了对象创建的管理,没有考虑到对象销毁的管理。就支持垃圾回收的平台和
4、对象的开销来讲,我们一般没有必要对其销毁做特殊的管理。不能应对多线程环境:在多线程环境下,使用Singleton模式仍然有可能得到Singleton类的多个对象。,4.9 模式编程介绍,简单工厂(Simple Factory)模式 new的问题常规的对象创建方法:A a=new A();new的问题:实现依赖,不能应对“具体实例化类型”的变化。解决思路:封装变化点(哪里变化,封装哪里)。潜台词:如果没有变化,当然不需要额外的封装。,4.9 模式编程介绍,简单工厂(Simple Factory)模式工厂模式的缘起变化点在对象创建,因此就封装对象创建。面向接口编程依赖接口,而非依赖具体实现。Sim
5、ple Factory模式(又称Static Factory模式)就是应用的这种方式。一个Simple Factory生产成品,而对客户端隐藏产品产生的细节。实现时定义一个产品接口(interface),并透过特定静态方法来建立成品。,4.9 模式编程介绍,简单工厂(Simple Factory)模式假设有一个八音盒工厂,购买八音盒的客人不用知道八音盒是如何制作的,他只要知道如何播放八音盒就可以了,以 UML 类别图来表示以上的概念:,父类Sample 子类 MySample MySampleSample mysample=new MySample();Sample hissample=new
6、 HisSample();public class Factorypublic static Sample creator(int which)/getClass 产生Sample 一般可使用动态类装载装入类。if(which=1)return new SampleA();else if(which=2)return new SampleB();Sample sampleA=Factory.creator(1);,1.4 设计模式介绍,结构(Structural)模式如何设计对象之间的静态结构,如何完成对象之间的继承、实现与依赖关系,这关乎着系统设计出来是否健壮(robust):像是易懂、易维
7、护、易修改、耦合度低等等议题。Structural 模式正如其名,其分类下的模式给出了在不同场合下所适用的各种对象关系结构。适配器(Adapter)模式桥(Bridge)模式组合(Composite)模式,1.4 设计模式介绍,适配器(Adapter)模式适配(转换)的概念无出不在适配,即在不改变原有实现的基础上,将原先不兼容的接口转换为兼容的接口。,1.4 设计模式介绍,适配器(Adapter)模式动机:在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同
8、时又能满足新的应用环境所要求的接口?适配器(Adapter)模式可以分为以下三种:1.默认适配器(Default Adapter)模式2.对象适配器(Object Adapter)模式3.类适配器(Class Adapter)模式,1.4 设计模式介绍,适配器(Adapter)模式将一个类的接口转换成客户希望的另一个借口。Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。设计模式GoF类适配器(Adapter)模式的UML结构图如下所示:,1.4 设计模式介绍,Adapter模式的几个要点1.Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境不
9、一致”的情况,在遗留代码重用、迁移类库方面有用。2.类适配器采用“多继承”方式,带来了高耦合,不推荐使用。对象适配器采用“对象组合”的方式,更符合“松耦合”精神。3.Adapter模式实现方式可以非常灵活。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数来达到适配的效果。4.Adapter模式本身要求我们尽可能地使用“面向接口编程”的风格,这样才能在后期很方便地适配。,1.4 设计模式介绍,桥(Bridge)模式抽象与实现抽象不应该依赖于实现细节,实现细节应该依赖于抽象。抽象A稳定 实现细节b变化问题在于如果抽象B由于固有的原因,本身也不稳定,也可能面临变化,这时怎么办?
10、,1.4 设计模式介绍,桥(Bridge)模式举例来说,假如我们需要开发一个同时支持PC和电视的坦克游戏,游戏在PC和电视上的功能都一样,都有同样的类型,都面临同样的功能需求变化,比如坦克有多种不同的型号:A,B,C等等。对于坦克的设计,我们能够很容易的设计出来一个坦克的接口,然后不同类型的坦克都实现这个接口:/抽象部分/各种坦克的实现public interface ITank public class TankA implementsITank/public void shot();public class TankB implementsITank/public void move();
11、public class TankC implementsITank/抽象部份指的是行为方面定义,实现方面指的是与特定平台相依的代码实现。,1.4 设计模式介绍,桥(Bridge)模式另外变化的原因PC和电视上的图形绘制、声效、操作等实现都不一样,因此对于各种型号的坦克,都要提供各种不同平台上的具体实现。这样的设计会有很多问题:有很多重复代码,类的结构过于复杂,难以维护,最致命的是如果引入任何新的平台,比如手机上的坦克游戏,都会让整个类的层次结构变的异常复杂。,1.4 设计模式介绍,桥(Bridge)模式动机思考上述问题的症结所在:事实上,由于Tank类型的固有逻辑,使得Tank类型具有了两个
12、变化的维度一个维度的变化为型号的变化,一个维度的变化是运行平台的变化。如何应对这种“多维的变化”?如何运用面向对象的技术使得Tank类型可以轻松地沿着“型号”和“平台”两个方向来变化,而不引入额外的复杂度?“将抽象部份与它的实现部份分离,使它们都可以独立地变化。”设计模式GoF,1.4 设计模式介绍,桥(Bridge)模式桥(Bridge)模式的要点1.Bridge模式使用“对象间的组合关系”解耦了抽象与实现之间固有的绑定关系,使得抽象(Tank的型号)和实现(不同的平台)可以沿着各自的维度来变化。2.所谓抽象和实现沿着各自的维度变化,即“子类化”它们。比如不同的Tank型号子类,和不同的平台
13、子类。得到各个子类之后,便可以任意组合它们,从而获得不同平台上的不同型号。3.Bridge模式一般应用在“两个非常强的变化纬度”,有时候即使有两个变化的纬度,但是某个方向的变化纬度并不剧烈换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。,1.4 设计模式介绍,组合(Composite)模式在面向对象系统中,我们经常会遇到一些具有“容器”特征的对象即它们在充当对象的同时,又是其它对象的容器。,1.4 设计模式介绍,组合(Composite)模式处理这样问题的一般方法是在作为容器的对象中使用诸如ArrayList等集合类,在客户端代码中判断该对象是否是对象容器,然后再进行相应
14、的处理。动机上述问题的根源在于:客户代码过多地依赖于容器对象内部的复杂结构,一旦发生变化,将会引起客户端代码的大量变动。如何让客户代码像使用简单对象一样来使用对象容器呢?将对象组合成树型结构以表示“整体-部分”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。设计模式GoF,1.4 设计模式介绍,组合(Composite)模式Composite 模式的要点:1.Composite 模式采用树形来实现普遍存在的容器对象,从而将“一对一”的关系转化成“一对多”的关系,使得客户代码一致地处理对象和对象容器,无须关心是单个对象还是容器对象。2.将“客户代码与复杂的对象容器”解
15、耦是Composite 模式的核心思想。解耦之后,客户代码将与纯粹的抽象接口而非对象容器的复杂内部结构发生依赖关系,从而更能应对变化。,2.7 设计模式,装饰(Decorator)模式假如我们要为一款游戏开发一种坦克,除了要有不同的型号外,还希望使不同型号的坦克能够在不同的场合动态地增加功能:比如红外线、特殊材料的钢板等等。一般的作法如下:/坦克接口/各种不同功能的组合public interface ITank public class Tank1A implements ITank,IApublic void shot();public class Tank2A implements IT
16、ank,IA/各种坦克的型号public class Tank1 implements ITank/public class Tank2 implements ITank/,2.7 设计模式,装饰(Decorator)模式动机:这种作法的问题在于:随着需要增加的功能的增加,需要继承或实现的抽象类或接口会不断增加,会导致子类的增加,如果要对不同的功能进行组合,将会导致更多的子类的膨胀。如何使“对象功能的扩展”能够根据需要动态地实现?同时避免子类膨胀问题?从而使得“扩展功能变化”导致的影响降为最低?动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。设计模
17、式GoF,2.7 设计模式,装饰(Decorator)模式装饰(Decorator)模式的UML结构图如下:,2.7 设计模式,装饰(Decorator)模式装饰(Decorator)模式的几个要点:1.通过采用组合而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。2.Component类在Decorator模式模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类相对于Component类应该透明换言之Component类无需知道Decorator类,Decorator类是从外部扩展Component类的功能。3.
18、Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”是为“装饰”的含义。,2.7 设计模式,外观(Facade)模式系统的复杂度假设我们开发一个坦克模拟系统用于模拟坦克在各种不同的作战环境中的行为,其中坦克系统由引擎、控制器、车轮、车身等各子系统构成。如何设计这样的系统 A方案 B方案,2.7 设计模式,外观(Facade)模式动机上述A方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和子系统的演化,这种过多的耦合面临很多变化的挑战。如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?为子系统
19、中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。设计模式GoF,2.7 设计模式,外观(Facade)模式外观(Facade)模式的UML结构图如下:,2.7 设计模式,外观(Facade)模式外观(Facade)模式的几个要点:1.从客户程序的角度看,Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某中程度上也达到了一种“解耦”的效果内部子程序的任何变化都不会影响到Facade接口的变化。2.Facade模式更注重从架构的层次上看待系统,而不是单个类的层次。Facade模式更是多的时候一种架构设计模式
20、。,小结,面向对象分析方法使得软件工程师能够通过对对象、属性和操作的表示来建模。面向对象分析发生在不同层次。对象关系模型展示了对象之间的连接对象行为模型指明了个体对象的行为和OO系统的整体行为。Decorator模式能够动态地为对象增加新功能。Facade模式为子系统中的一组接口提供一个一致的界面,定义了一个高层接口,这个接口使得这一子系统更加容易使用。,模式编程介绍,行为模式对象之间的合作行为构成了程序最终的行为,对象之间若有设计良好的行为互动,不仅使得程序执行时更有效率,更可以让对象的职责更为清晰、整个程序的动态结构(像是对象调度)更有弹性。在这里主要介绍如下几种行为模式:模板(Templ
21、ate Method)模式命令(Command)模式责任链(Chain of Responsibility)模式,模式编程介绍,模板(Template Method)模式无处不在的Template Method!如果你只想掌握一种设计模式,那么它就应该是Template Method!,模式编程介绍,模板(Template Method)模式变与不变变化是软件设计的永恒主题。如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何分析,并通过分析发现系统中的变化点和稳定点,并使用特定的方法来应对这种变化。,模式编程介绍,模板(Template Method)模式动机在软件构件过程中,对于某
22、一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多变化的需求,或者由于固有的原因而无法和任务的整体结构同时实现。如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期的实现需求?定义一个操作中的算法的骨架,而将这些步骤延迟到子类中。Template Method模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。设计模式Gof,模式编程介绍,模板(Template Method)模式模板(Template Method)模式的UML结构图如下:,模式编程介绍,模板(Template Method)模式模板(Template Method)模式的几个要点:1.
23、Template Method模式是一种非常基础性的模式,在面向对象的系统中有着大量的应用。它用最简洁的机制,为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本结构框架。2.除了可以灵活地应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method模式的典型应用。,模式编程介绍,命令(Command)模式耦合与变化耦合是软件不能抵御变化灾难的根本原因。不仅对象实体与对象实体之间存在着耦合关系,实体对象与行为操作之间也存在着偶合关系。,模式编程介绍,命令(Command)模式动机在软件构建过程中,“行为请求者”与“行为实现者”之间通常呈现出一种“紧耦合”
24、。但是在某些场合,比如需要对行为进行“记录、撤消、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为”实现者解耦?将一组行为抽象成对象,可以实现二者之间的松耦合。将一个请求封装为一个对象,从而使你用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。设计模式GoF,模式编程介绍,命令(Command)模式命令(Command)模式的UML结构图如下:,模式编程介绍,命令(Command)模式命令(Command)模式的几个要点:1.Command模式的根本目的在于将“行为请求者”与“行为实现者”之间解耦。在面向对象语言中,常见的
25、实现手段是“将行为抽象为对象”。2.实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能回保存一些额外的信息。,模式编程介绍,责任链(Chain of Responsibility)模式请求的发送者与接收者某些对象请求的接收者可能多种多样,变化无常.,模式编程介绍,责任链(Chain of Responsibility)模式动机在软件构件过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接收者。如果显示指定,将必不可少地带来请求发送者与接收者的紧耦合。如何使请求的发送者不需要指定请求的接收者?让请求的接收者自己在运行时决定来处理请求,从而将二者解
26、耦。使多个对象都有机会处理请求,以避免请求的发送者与接收者之间的耦合关系,将这些对象组合为一个链,并沿着这个链传递该请求,直到有一个对象处理它为止。设计模式GoF,模式编程介绍,责任链(Chain of Responsibility)模式责任链(Chain of Responsibility)模式的UML结构图如下:,模式编程介绍,责任链(Chain of Responsibility)模式责任链(Chain of Responsibility)模式的要点:1.Chain of Responsibility模式的应用场合在于“一个请求可能有多个接收者,但是最后真正的接收者只有一个”,只有这时候
27、请求发送者与请求接收者的耦合才有可能出现“变化脆弱”的症状。责任链的目的就是在于将二者解耦,从而更好地应对变化。2.应用了Chain of Responsibility模式后,对象的职责分派将更具有灵活性。3.如果请求传递到责任链的末尾仍然的不到处理,应该有一个合理的缺省机制。着也是每一个接受对象的责任,而不是发出请求的对象的责任。,章节安排,状态(State)模式中介者(Mediator)模式备忘录(Memento)模式观察者(Observer)模式策略(Strategy)模式访问者(Visitor)模式,6.1 状态(State)模式,对象的状态影响对象的行为对象拥有不同的状态,往往会行使
28、不同的行为,6.1 状态(State)模式,动机在软件构建过程中,对象的状态往往会影响对象的行为。也就是说,对象会拥有不同的状态,因此往往会行使不同的行为。某些对象的状态如果改变,其行为也会随之变化。比如一个文档处于只读的状态,其支持的行为和读写状态支持的行为就可能完全不同。如何在运行是根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?,6.1 状态(State)模式,意图允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。设计模式GoF,6.1 状态(State)模式,状态(State)模式的UML结构类图如下:,6.1 状态(Stat
29、e)模式,使用状态(State)模式的几个要点:State模式将所有与一个特定状态相关的行为都方入一个State的子类对象中,在对象状态切换时,切换相应对象;但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。为不同的状态引入不同的对象使得状态转换变的更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的要么彻底转换过来,要么不转换。,6.2 中介者(Mediator)模式,依赖关系的转化,6.2 中介者(Mediator)模式,动机在软件构建过程中,经常会出现多个相互关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将
30、面临不断的变化。在这种情况下,我们可以使用一个“中介者对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合的引用关系,从而更好地抵御变化。,6.2 中介者(Mediator)模式,意图用一个中介对象来封装一系列对象的交互。中介者使得各对象不需要显示的互相引用,从而使得其耦合松散,而且可以独立地改变他们之间的交互。设计模式GoF,6.2 中介者(Mediator)模式,中介者(Mediator)模式的UML结构类图如下:,6.2 中介者(Mediator)模式,中介者(Mediator)模式的几个要点:将多个对象间复杂的关联关系解耦,Mediator模式将多个对象的控制逻辑进行集中管理,
31、变“多个对象相互关联”为“多个对象与一个中介者对象关联”,简化了系统的维护,抵御了可能的变化。随着控制逻辑的复杂化,Mediator具体对象的实现可能变得相当复杂,这时候可以对Mediator对象进行分解处理。Facade模式是解耦系统外到系统内(单向)的对象关联关系;Mediator模式是解耦系统内各个对象间(双向)的关联关系。,6.2 备忘录(Memento)模式,对象状态的回溯对象状态的变化无端,如何回溯/恢复对象在某个点的状态?,6.2 备忘录(Memento)模式,动机在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点的状态。如果使用
32、一些公有接口来让其他对象得到对象的状态,势必会暴露对象的实现细节。如何实现对象状态的良好保存与恢复,但同时又不会因此而破坏对象本身的封装性?,6.2 备忘录(Memento)模式,意图在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先的状态。设计模式GoF,6.2 备忘录(Memento)模式,备忘录(Memento)模式的UML结构图如下:,6.2 备忘录(Memento)模式,备忘录(Memento)模式备忘录(Memento)模式的几个要点:备忘录(Memento)存储原发器(Original)对象的内部状态,在需要时恢复原发器状
33、态。Memento模式适用于“有原发器管理,却有必须存储在原发器之外的信息”。在实现Memento模式中,要防止原发器以外的对象访问备忘录对象。备忘录对象有两个接口,一个为原发器使用的宽接口;一个为其他对象使用的窄接口。,6.3 观察者(Observer)模式,发布订阅模型,6.3 观察者(Observer)模式,动机在软件构建过程中,我们需要为某些对象建立一种“通知依赖”关系,即,一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系,从而实现软件
34、体系结构的送耦合。,6.3 观察者(Observer)模式,意图定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。设计模式GoF,6.3 观察者(Observer)模式,观察者(Observer)模式的UML结构图如下:,6.3 观察者(Observer)模式,观察者(Observer)模式观察者(Observer)模式的几个要点:使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到送耦合。目标发出通知使,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。观察者自己决定是否需要
35、订阅通知,目标对象对此一无所知。,6.4 策略(Strategy)模式,算法与对象的耦合对象可能经常需要使用多种不同的算法,但是如果变化的频繁,会将类变得脆弱,6.4 策略(Strategy)模式,动机在软件构建过程中,某些对象使用的算法可能多种多做样,经常变化,如果将这些算法都编码到对象中,将会是对象变的异常复杂。而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法?将对象与算法本身解耦,从而避免上述问题?,6.4 策略(Strategy)模式,意图定义一系列算法,将他们一个个地封装起来,并且使他们可以互相替换。这种模式使得算法可以独立于使用它的客户而变化。设
36、计模式GoF,6.4 策略(Strategy)模式,策略(Strategy)模式的UML结构类图如下:,6.4 策略(Strategy)模式,策略(Strategy)模式的几个要点:Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类在运行时方便地根据需要在各个算法之间进行切换。所谓封装算法,支持算法的变化。Strategy模式提供了条件判断以外的另一种选择,消除条件判断语句,就是在解耦。含有很多条件判断语句的代码通常都需要Strategy模式。,6.5 访问者(Visitor)模式,类层次结构的变化类层次结构中可能经常由于引入新的操作,从而使类型变得脆弱,6.5 访问者(V
37、isitor)模式,动机在软件构建过程中,由于需求的改变,某些层次的结构中常常要增加新的行为,如果直接在基类中做这些更改,将会给子类带来很繁重的变更负担,甚至破坏原有的设计。如何在不改变类层次结构的前提下,在运行时根据需要透明地为类的层次结构上的各个类动态地添加新功能,从而避免上述问题?,6.5 访问者(Visitor)模式,意图表示一个作用于某对象结构中各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。设计模式GoF,6.5 访问者(Visitor)模式,访问者(Visitor)模式的UML结构类图如下:,6.5 访问者(Visitor)模式,访问者(Visitor)模式的几个要点:Visitor模式通过所谓双重分发来实现在不改变Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类添加新的操作。所谓双重分发即Visitor模式中间包括了两个多态分发:第一个为accept方法的多态辨析;第二各为visit方法的多态辨析。Visitor模式的最大缺点就是扩展了类的层次结构(增加了新的Element子类),会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定,而其中的操作却面临频繁的变动。”,