Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4241787
  • 博文数量: 176
  • 博客积分: 10059
  • 博客等级: 上将
  • 技术积分: 4681
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-24 12:27
文章分类

全部博文(176)

文章存档

2012年(1)

2011年(4)

2010年(14)

2009年(71)

2008年(103)

分类: 项目管理

2008-06-24 17:42:38

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


本文介绍设计模式中的(Visitor)模式的概念,用法,以及实际应用中怎么样使用Visitor模式进行开发。
Visitor模式的概念
Visitor模式是一种分离对象数据结构与行为的方法,通过这种分离,可以为一个已存在的类或类群增加新的操作而无需为它们作任何修改。
Visitor模式UML类图

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 {

    /**
     * Test Visitor Pattern
     *
     */

    public static void main(String[] args) {
        //创建复合对象(公园对象)
        Park park = new Park("Park");
        
        //创建打扫A部分的清洁工访问者
        System.out.println("---Visitor: CleanerA---");
        Visitor visitorCleanerA = new VisitorCleanerA();
        park.accept(visitorCleanerA);
        
        //创建打扫B部分的清洁工访问者
        System.out.println("---Visitor: CleanerB---");
        Visitor visitorCleanerB = new VisitorCleanerB();
        park.accept(visitorCleanerB);
        
        //创建管理公园的管理人访问者
        System.out.println("---Visitor: Manager---");
        Visitor visitorManager = new VisitorManager();
        park.accept(visitorManager);
        
    }
}

/**
* Visitor Role
*
*/

interface Visitor {
    void visit(Park park);
    void visit(ParkPartA parkPartA);
    void visit(ParkPartB parkPartB);
}

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

class VisitorCleanerA implements Visitor {

    public void visit(Park park) {}

    public void visit(ParkPartA parkPartA) {
        System.out.println("Clean " + parkPartA.name);
    }

    public void visit(ParkPartB parkPartB) {}
}

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

class VisitorCleanerB implements Visitor {

    public void visit(Park park) {}

    public void visit(ParkPartA parkPartA) {}

    public void visit(ParkPartB parkPartB) {
        System.out.println("Clean " + parkPartB.name);                
    }
}

/**
* ConcreteVisitor
* 公园的管理人员类
*
*/

class VisitorManager implements Visitor {

    public void visit(Park park) {
        System.out.println("Check " + park.name);
    }

    public void visit(ParkPartA parkPartA) {
        System.out.println("Check " + parkPartA.name);
    }

    public void visit(ParkPartB parkPartB) {
        System.out.println("Check " + parkPartB.name);
    }
}


/**
* Element Role
*
*/

interface Visitable {
    void accept(Visitor visitor);
}

/**
* ObjectStructure & ConcreteElement Role
* 公园类,包含ParkPartA与ParkPartB部分
*
*/

class Park implements Visitable {
    String name;
    ParkPartA parkPartA = new ParkPartA("ParkPartA");
    ParkPartB parkPartB = new ParkPartB("ParkPartB");;
    
    public Park(String name) {
        this.name = name;
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
        
        parkPartA.accept(visitor);
        parkPartB.accept(visitor);
    }
}

/**
* ConcreteElement Role
* 公园的一部分ParkPartA
*
*/

class ParkPartA implements Visitable {
    String name;
    
    public ParkPartA(String name) {
        this.name = name;
    }
    
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

/**
* ConcreteElement Role
* 公园的一部分ParkPartB
*
*/

class ParkPartB implements Visitable {
    String name;
    
    public ParkPartB(String name) {
        this.name = name;
    }
    
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}



执行Client,输出结果:
C:\Visitor>javac *.java
C:\Visitor>java Client
---Visitor: CleanerA---
Clean ParkA
---Visitor: CleanerB---
Clean ParkB
---Visitor: Manager---
Check Park
Check ParkA
Check ParkB
C:\Visitor>
不同的访问者执行不同的行为,而且行为与数据本身完全分开了。当需要新增加一个访问者时,只需要创建一个实现Visitor接口的新类就可以了。
阅读(3095) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-05-11 21:16:35

这个例子有问题吧?如果公园有partC部分,那么visit的接口要更改。 而且具体访问者,有些操作实际上是空操作。