MyException - 我的异常网
当前位置:我的异常网» 设计模式 » 设计形式之 Visitor - 访问者模式

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

www.MyException.Cn  网友分享于:2013-08-27  浏览:1次
设计模式之 Visitor - 访问者模式

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接口的新类就可以了。

文章评论

为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
编程语言是女人
编程语言是女人
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
代码女神横空出世
代码女神横空出世
 程序员的样子
程序员的样子
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
鲜为人知的编程真相
鲜为人知的编程真相
Java程序员必看电影
Java程序员必看电影
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
总结2014中国互联网十大段子
总结2014中国互联网十大段子
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
程序员必看的十大电影
程序员必看的十大电影
中美印日四国程序员比较
中美印日四国程序员比较
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
如何成为一名黑客
如何成为一名黑客
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
我的丈夫是个程序员
我的丈夫是个程序员
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
为什么程序员都是夜猫子
为什么程序员都是夜猫子
程序员的鄙视链
程序员的鄙视链
每天工作4小时的程序员
每天工作4小时的程序员
10个调试和排错的小建议
10个调试和排错的小建议
程序员都该阅读的书
程序员都该阅读的书
漫画:程序员的工作
漫画:程序员的工作
我是如何打败拖延症的
我是如何打败拖延症的
那些争议最大的编程观点
那些争议最大的编程观点
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
老程序员的下场
老程序员的下场
程序员和编码员之间的区别
程序员和编码员之间的区别
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
程序员应该关注的一些事儿
程序员应该关注的一些事儿
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有