Java设计模式(三) Visitor(访问者)模式及多分派场景应用

原创 2016年04月14日 15:32:41

基本概念

Visitor

  • 封装一些作用于数据结构中的各元素的操作,不同的操作可以借助新的visitor实现,降低了操作间的耦合性
  • 访问者可以将数据结构对数据的操作解耦,使得增加对数据结构的操作不需要取修改数据结构,也不必去修改原有的操作,而执行时再定义新的Visitor时闲着就行了(在操作添加上易拓展)

模式中角色分工

  • Visitor:抽象访问者,在重载的visit函数中声明访问者可以访问的对象
  • Concrete Visitor:实现一个访问者对于一个具体的元素的操作
  • Element:抽象元素,声明具有访问该类型元素权限的访问者的类型(一般是抽象类型),提供重载的accept函数赋予权限
  • Concrete Element:实现accept方法,基本上是模板化的visitor.visit(this)
  • Object Structure:容纳多种类型或许不同,接口或者不同的元素的集合。

例讲Visitor的实现

先是一个简单的例子,展现一个最基本的简陋的Visitor

既然在春招季,我们举个简历筛选的例子,投简历的都是写本科生、专科生,还有硕士生、高职啊…为了简单就先取前两者。求职者的简历作为Element实现如下:

abstract class Student {
   //提供对于数据域基本操作的函数
    private String name;
    private String university;
    private String rating;
    //让指定的visitor获得操作该对象的权限
    public abstract void accept(Visitor visitor);

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUniversity() {
        return university;
    }

    public void setUniversity(String university) {
        this.university = university;
    }

    public String getRating() {
        return rating;
    }

    public void setRating(String rating) {
        this.rating = rating;
    }
}

class Bachelor extends Student{

    @Override
    public void accept( Visitor visitor ) {
        visitor.visit( this );
    }
}

class College extends Student{

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

因为我们只定义了两种学生,所以接口提供了对于两种Element访问

interface Visitor{
    public void visit ( Bachelor bachelor );
    public void visit ( College college );
}

首先筛选简历我们看一下大家的简历都什么样子,那么需要一个ShowVisitor:

class ShowVisitor implements Visitor {

    @Override
    public void visit(Bachelor bachelor) {
        System.out.println("A bachelor\n");
        //TODO 可能会有一些特异的操作,我们为了简单就省略了
        this.printMessage( bachelor );
    }

    @Override
    public void visit(College college) {
        System.out.println(" a college student!\n");
        //TODO 同上
        this.printMessage( college );
    }

    public void printMessage ( Student student ){
        System.out.println( "Name : " + student.getName()+"\n"
                + "University : " + student.getUniversity()+"\n"
                + "Rating : " + student.getRating() + "\n"
        );
    }
}

要进行测试,我们首先要构造一个数据集合,也就是角色中对应的ObjectStructure,为了简单我们直接用ArrayList了

public class VisitorEg {
    public static void main ( String [] args ){
        ArrayList<Student> list = new ArrayList<Student>();
        Bachelor bachelor = new Bachelor();
        bachelor.setName("llin");
        bachelor.setRating("100");
        bachelor.setUniversity("Tianjin University");

        College college = new College();
        college.setUniversity("Tianjin college");
        college.setRating("1");
        college.setName("dalinge");

        list.add ( bachelor );
        list.add ( college );

        Visitor visitor = new ShowVisitor();
        for ( Student student: list ){
            student.accept( visitor );
        }

    }
}

那么好像看不出访问者模式有什么优势啊!!!而且好费事啊,但是因为你将数据结构和对数据的操作分离了(解耦),所以当我想添加新的操作时,不需要修改原有的类,只需要重新实现一个visitor就可以了。


所以,我们回到这个例子,这么多人报名,那么到底有多少本科生呢(如果人数够了,可能直接偷懒只面试本科生了),-_-万恶的这种HR,所以我们需要一个统计的Visitor:

class SumVisitor implements Visitor{

    private int totalBachelor;

    SumVisitor(){
        super();
        totalBachelor = 0;
    }

    @Override
    public void visit(Bachelor bachelor) {
        totalBachelor++;
    }

    @Override
    public void visit(College college) {
    }

    public int getTotal_bachelor() {
        return totalBachelor;
    }
}

public class VisitorEg {
    public static void main ( String [] args ){
        ArrayList<Student> list = new ArrayList<Student>();
        Bachelor bachelor = new Bachelor();
        bachelor.setName("llin");
        bachelor.setRating("100");
        bachelor.setUniversity("Tianjin University");

        College college = new College();
        college.setUniversity("Tianjin college");
        college.setRating("1");
        college.setName("dalinge");

        list.add ( bachelor );
        list.add ( college );

        Visitor visitor = new ShowVisitor();
        Visitor visitor1 = new SumVisitor();
        for ( Student student: list ){
            student.accept( visitor );
            student.accept( visitor1);
        }
        System.out.println( "The total sum of bachelors : "+ ((SumVisitor)visitor1).getTotal_bachelor() );
    }
}

达到了要求,却没有修改一行代码,开心!

Visitor应用场景

一定会有的疑问:visitor和iterator的区别:

  • visitor可以访问不同的对象(只需要在Element定义对应的accept),但是Iterator只能访问相同的对象,最起码要有相同的接口
  • iterator是不依赖具体实现的,而visitor是依赖具体实现的,因为Visitor会根据访问的具体的对象来采取对应的操作,而iterator最多只是基于相同的接口的泛化实现。
  • iterator访问的数据结构的操作和数据并未分离,所以拓展功能起来需要修改,违反了开闭原则单一职责原则。但是因为访问者依赖具体实现,而不是依赖抽象,所以违反了依赖倒置原则

优缺点决定的应用场景

  • 符合单一职责原则,功能上具有良好的拓展性,但是因为依赖具体实现违背了具体实现,所以为类的修改带了麻烦。
  • 具有优良的拓展性,只需要实现新的Visitor来满足新的访问要求。因为数据和操作的分离,防止了添加新的操作污染原来的数据结构。

综上

访问者是一种集中规整模式,特别适合用于大规模重构的项目,在这一个阶段的需求已经非常清晰,原系统的功能点也已经明确,通过访问者模式可以很容易把一些功能进行梳理,达到最终目的功能集中化

双分派

首先介绍以下单分派

单分派:一个操作是根据请求者的名称和接收到的参数决定的,在Java有静态绑定动态绑定,分别是通过重载覆写实现的。
双分派:双分派意味着得到执行的操作决定于请求的种类接收者的类型。正对应于访问者模式

Javac在构建、优化、解析语法树的时候就是采用的是Visitor模式(语法、语义分析阶段)

版权声明:本文为博主原创文章,未经博主允许不得转载。

设计模式读书笔记-----访问者模式

生老病死乃常态,是我们每个人都逃脱不了的,所以进医院就是一件再平常不过的事情了。在医院看病,你首先的挂号,然后找到主治医生,医生呢?先给你稍微检查下,然后就是各种处方单(什么验血、CD、B超等等,太坑...
  • chenssy
  • chenssy
  • 2013年09月25日 21:31
  • 9441

23种设计模式(9):访问者模式

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 类型:行为类模式 类图:        访问者模式可能是行为类模式中最复杂的一种...
  • zhengzhb
  • zhengzhb
  • 2012年04月23日 14:49
  • 59370

JAVA设计模式十四--Visitor(访问者模式)

访问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式。 据《大话设计模式》中说算是最复杂也是最难以理解的一种模式了。    定义(源于GoF《Design...
  • hfmbook
  • hfmbook
  • 2012年06月22日 10:20
  • 8953

JAVA设计模式之Visitor模式

一个集合(Collection)中,可以包含一个Car,也可以包含一个Cat,对于不同类型的元素,他们的行为也不尽相同,比如,Car可能有start()行为,而Cat可能有eat()的行为。可是对于C...
  • chenjie19891104
  • chenjie19891104
  • 2011年05月04日 13:46
  • 13540

浅谈JAVA设计模式之——访问者模式(Visitor)

一、概述 表示一个作用于某对象结构中的各元素的操作。 它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 二、适用性 1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实...
  • l1028386804
  • l1028386804
  • 2015年05月09日 14:27
  • 1080

JAVA设计模式之 访问者模式【Visitor Pattern】

一、概述     访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。在使用访问者...
  • l416112167
  • l416112167
  • 2014年11月15日 22:21
  • 3342

设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)

特此说明:对访问者模式理解不是特别透彻,若有误,请指正,谢谢! 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集...
  • hguisu
  • hguisu
  • 2012年05月14日 16:00
  • 11821

设计模式总结之Visitor Pattern(访问者模式)

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。...
  • cooldragon
  • cooldragon
  • 2016年08月12日 12:10
  • 4174

设计模式:VISITOR模式

最近在项目中用到了VISITOR模式,总结一下,自己也再学习一遍,同时和大家分享。 我最初遇到设计模式的时候,有这些疑问:什么设计模式在什么情况下可以解决什么问题?设计模式的最大特点是抽象,并不难,...
  • u012142787
  • u012142787
  • 2014年09月28日 20:09
  • 981

C#面向对象设计模式纵横谈(24):(行为型模式) Visitor 访问者模式

  • 2008年09月16日 14:47
  • 9.25MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java设计模式(三) Visitor(访问者)模式及多分派场景应用
举报原因:
原因补充:

(最多只允许输入30个字)