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

基本概念

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来满足新的訪问要求。

    由于数据和操作的分离,防止了加入新的操作污染原来的数据结构。

综上

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

双分派

首先介绍下面单分派

单分派:一个操作是依据请求者的名称和接收到的參数决定的,在Java有静态绑定动态绑定,各自是通过重载覆写实现的。

双分派:双分派意味着得到运行的操作决定于请求的种类接收者的类型

正相应于訪问者模式

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

时间: 2024-10-22 20:48:53

Java设计模式(三) Visitor(訪问者)模式及多分派场景应用的相关文章

《Java设计模式》之訪问者模式

訪问者模式是对象的行为模式.訪问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作须要改动的话,接受这个操作的数据结构则能够保持不变. 分派的概念 变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type):而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type).比方 [java] view plaincopyprint" class="About" href="

设计模式入门之訪问者模式Visitor

//訪问者模式定义:表示一个作用于某对象结构中的各个元素的操作.它使你能够在不改变各元素类的前提下定义作用于这些元素的新操作. //从定义上看,这个模式跟装饰模式的定义非常类似(动态地给一个对象加入一些额外的职责).可是装饰模式很多其它是在原有的基础上进行功能加强或者改动:而訪问者模式很多其它是为对象加入全新的功能.訪问者模式适合那些须要频繁为某些类加入新功能.新操作的项目. //模式结构: //Visitor:訪问者接口,为全部的訪问者对象声明一个visit方法,用来表示对对象结构加入的功能,

设计模式之十五:訪问者模式(Visitor Pattern)

訪问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式. 据<大话设计模式>中说算是最复杂也是最难以理解的一种模式了. 定义(源于GoF<Design Pattern>):表示一个作用于某对象结构中的各元素的操作.它使你能够在 不改变各元素类的前提下定义作用于这些元素的新操作.从定义能够看出结构对象是使用訪问者模式必备 条件,并且这个结构对象必须存在遍历自身各个对象的方法.这便类似于Java语言其中的collection概念了. 涉及角色 :

设计模式之二十四:訪问者模式(Visitor)

訪问者模式: 定义了一个作用于一个类的一些操作,訪问者模式同意在不改变类的前提下添加一些操作. Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. UML类图: 主要包括: Vis

PHP设计模式——訪问者模式

声明:本系列博客參考资料<大话设计模式>,作者程杰. 訪问者模式表示一个作用于某对象结构中的各元素的操作. 它使你能够在不改变各元素类的前提下定义作用于这些元素的新操作. UML类图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamhxMDExMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > 角色: 1.抽象訪问者(

设计模式学习总结(21) 訪问者模式

本系列主要记录设计模式的意图是什么,它要解决一个什么问题,什么时候可以使用它:它是怎样解决的,掌握它的结构图,记住它的关键代码:可以想到至少两个它的应用实例,一个生活中的,一个软件中的:这个模式的优缺点是什么,其有哪些使用场景,在使用时要注意什么. 尊重作者,转载请注明晔阳的Bloghttp://blog.csdn.net/hacke2 21.訪问者模式 意图:主要讲数据结构与数据操作分离 主要解决:稳定的数据结构和易变的操作耦合问题 什么时候使用:与类本不相关的,为了避免这个污染 ,使用訪问者

訪问者模式的分析、结构图及基本代码

 之前我对全部的23种设计模式作了一个小总结.如今我们来对每一种设计模式作具体的分析.首先是訪问者模式: 定义:表示一个作用于某对象结构中的各元素的操作.它可使你能够在不改变各元素的类的前提下定义作用于这些元素的新操作. 适用地方:訪问者模式的目的是要把处理从数据结构分离出来.非常多系统能够依照算法和数据结构分开,假设这种系统有比較稳定的数据结构.又有易于变化的算法的话.使用訪问者模式就是比較合适的,由于訪问者模式使得算法操作的添加变得easy. 优缺点:訪问者模式的长处就是添加新的操作非常

3.5 訪问者模式(5.11)

訪问者模式的学习.能够从以下方面入手. 假设一门编程语言支持双分派(多分派).那么訪问者模式就没有太大的存在价值.其实,看完Java模拟 双分派Double Dispatch,你应该自己做最后的题目:改动上述代码.使得消息a.foo(b),当中a声明为X类型变量.b声明为Z类型变量.题目做完了,訪问者模式你就自己搞出来了. 所以,--要在訪问者模式基础上玩花样时,我们再继续. 訪问者模式的意图,方便于给一个类增添新的接口. 为什么GoF要提到"某种对象结构"和元素呢?好多网上的样例,讲

Java 设计模式系列(二三)访问者模式(Vistor)

Java 设计模式系列(二三)访问者模式(Vistor) 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 一.访问者模式结构 访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化. 数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作.这样的过程叫做"双重分派