设计模式之 Visitor - 访问者模式

Backwardelements 2010-12-18

Visitor模式也叫访问者模式,是由GoF提出的23种软件设计模式的一种。Visitor模式是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的情况下,增加新的操作。

本文介绍设计模式中的(Visitor)模式的概念,用法,以及实际应用中怎么样使用Visitor模式进行开发。

Visitor模式的概念
Visitor模式是一种分离对象数据结构与行为的方法,通过这种分离,可以为一个已存在的类或类群增加新的操作而无需为它们作任何修改。

Visitor模式UML类图

设计模式之 Visitor - 访问者模式

Visitor

访问者抽象接口,通过visit(Element)方法访问Element(数据结构),完成对Element的操作行为。

ConcreteVisitor

访问者的具体实现类。

ObjectStructure

复合对象。包括所有需要被访问的数据结构对象(Element)。ObjectStructure本身也可以作为被访问者。

Element

元素,也就是被访问者。通过accept(Visitor)方法接受Visitor的访问。

ConcreteElement

Element的具体实现类。

Visitor模式的应用场景
我们举例来说明Visitor模式的应用场景。

比如有一个公园,有一到多个不同的组成部分;

该公园存在多个访问者:清洁工A负责打扫公园的A部分,清洁工B负责打扫公园的B部分,公园的管理者负责检点各项事务是否完成,上级领导可以视察公园等等。

也就是说,对于同一个公园,不同的访问者有不同的行为操作,而且访问者的种类也可能需要根据时间的推移而变化(行为的扩展性)。

根据软件设计的开闭原则(对修改关闭,对扩展开放),我们怎么样实现这种需求呢?

在这个例子中,如果我们在公园类里实现所有的访问者行为,势必造成以下问题:

1,由于所有的访问者的行为各不一样,在一个类中实现所有访问者行为,会造成该类功能过多,代码冗长。

2,不利于扩展。每增加一个访问者,就需要在已有的类里为其实现一个新的行为,就是说不得不修改已有的类,显然不符合软件设计开闭原则。

Visitor模式便可以解决这类问题。

当一个应用满足以下条件时,我们可以使用Visitor设计模式:

-一个对象可能存在一到多个数据元素

-存在多种行为,分别对不同的数据元素或数据的全体进行处理

-行为的不确定性或者说行为的扩展性

Visitor模式的优点
上面已经提到过Visitor模式的优点:

-分离对象的数据结构与行为,让不同的类完成不同的功能

-可以不修改已有类的基础上增加新的操作行为

-从另一个角度来看,同一个数据结构,为其实现不同的观察者,便可呈现不同的行为。

Visitor模式的实现步骤:
1,定义具有继承关系的数据结构对象群(相当于Element与ConcreteElement角色),并定义accept(Visitor)方法接受Visitor访问

2,定义包含上述数据结构对象群的复合结构对象(相当于ObjectStructure角色)

3,定义Visitor抽象接口,定义所有访问行为方法(相当于Visitor角色)

4,定义具体的访问者对象,并实现所有visit方法(相当于ConcreteVisitor角色)

Visitor模式的应用范例

文件一览:

Client

测试类。

Visitable

相当于Element角色。

Park

公园类,包含ParkPartA与ParkPartB部分。相当于ObjectStructure以及ConcreteElement角色。

ParkPartA

公园的ParkPartA部分。相当于ConcreteElement角色。

ParkPartB

公园的ParkPartB部分。相当于ConcreteElement角色。

Visitor

访问者抽象接口。相当于Visitor角色。

VisitorCleanerA

负责打扫ParkPartA部分的清洁工类。相当于ConcreteVisitor角色。

VisitorCleanerB

负责打扫ParkPartA部分的清洁工类。相当于ConcreteVisitor角色。

VisitorManager

公园的管理人员类。相当于ConcreteVisitor角色。

代码:

public class Client {

/**

*TestVisitorPattern

*

*/

publicstaticvoidmain(String[]args){

//创建复合对象(公园对象)

Parkpark=newPark("Park");

//创建打扫A部分的清洁工访问者

System.out.println("---Visitor:CleanerA---");

VisitorvisitorCleanerA=newVisitorCleanerA();

park.accept(visitorCleanerA);

//创建打扫B部分的清洁工访问者

System.out.println("---Visitor:CleanerB---");

VisitorvisitorCleanerB=newVisitorCleanerB();

park.accept(visitorCleanerB);

//创建管理公园的管理人访问者

System.out.println("---Visitor:Manager---");

VisitorvisitorManager=newVisitorManager();

park.accept(visitorManager);

}

}

/**

*VisitorRole

*

*/

interfaceVisitor{

voidvisit(Parkpark);

voidvisit(ParkPartAparkPartA);

voidvisit(ParkPartBparkPartB);

}

/**

*ConcreteVisitor

*负责打扫ParkPartA部分的清洁工类

*

*/

classVisitorCleanerAimplementsVisitor{

publicvoidvisit(Parkpark){}

publicvoidvisit(ParkPartAparkPartA){

System.out.println("Clean"+parkPartA.name);

}

publicvoidvisit(ParkPartBparkPartB){}

}

/**

*ConcreteVisitor

*负责打扫ParkPartB部分的清洁工类

*

*/

classVisitorCleanerBimplementsVisitor{

publicvoidvisit(Parkpark){}

publicvoidvisit(ParkPartAparkPartA){}

publicvoidvisit(ParkPartBparkPartB){

System.out.println("Clean"+parkPartB.name);

}

}

/**

*ConcreteVisitor

*公园的管理人员类

*

*/

classVisitorManagerimplementsVisitor{

publicvoidvisit(Parkpark){

System.out.println("Check"+park.name);

}

publicvoidvisit(ParkPartAparkPartA){

System.out.println("Check"+parkPartA.name);

}

publicvoidvisit(ParkPartBparkPartB){

System.out.println("Check"+parkPartB.name);

}

}

/**

*ElementRole

*

*/

interfaceVisitable{

voidaccept(Visitorvisitor);

}

/**

*ObjectStructure&ConcreteElementRole

*公园类,包含ParkPartA与ParkPartB部分

*

*/

classParkimplementsVisitable{

Stringname;

ParkPartAparkPartA=newParkPartA("ParkPartA");

ParkPartBparkPartB=newParkPartB("ParkPartB");;

publicPark(Stringname){

this.name=name;

}

publicvoidaccept(Visitorvisitor){

visitor.visit(this);

parkPartA.accept(visitor);

parkPartB.accept(visitor);

}

}

/**

*ConcreteElementRole

*公园的一部分ParkPartA

*

*/

classParkPartAimplementsVisitable{

Stringname;

publicParkPartA(Stringname){

this.name=name;

}

publicvoidaccept(Visitorvisitor){

visitor.visit(this);

}

}

/**

*ConcreteElementRole

*公园的一部分ParkPartB

*

*/

classParkPartBimplementsVisitable{

Stringname;

publicParkPartB(Stringname){

this.name=name;

}

publicvoidaccept(Visitorvisitor){

visitor.visit(this);

}

}

执行Client,输出结果:

C:\Visitor>javac *.java

C:\Visitor>javaClient

---Visitor:CleanerA---

CleanParkA

---Visitor:CleanerB---

CleanParkB

---Visitor:Manager---

CheckPark

CheckParkA

CheckParkB

C:\Visitor>

不同的访问者执行不同的行为,而且行为与数据本身完全分开了。当需要新增加一个访问者时,只需要创建一个实现Visitor接口的新类就可以了。

相关推荐