为什么80%的码农都做不了架构师?>>>   

摘要

设计模式是对设计原则的具体实践,在编码过程中我们要牢记设计原则,根据当前需求灵活选用我们要使用的设计模式。Visitor Pattern 是一个不常用的模式,在我看来,visitor pattern 也算是面向对象里的一种奇技淫巧了。

what

什么是visitor模式?从Wikipedia 上的定义为:In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates.. 是将算法与类结构分开的这么一种模式,而且是面向对象独有的。

When

我们在什么条件下才可以使用这个模式呢?有以下几个方面需要满足:

  • 有一组提前定义好的类(已知)
  • 对象上的操作是未知的
  • 对象需要根据不同的类做出不同的操作,因此需要使用(instanceof)判断

操作就是定义中的algorithm,提前定义好的类就是object structure。也就是说由于操作未知,所以将原本属于类中的操作拿出来,放到 visitor 中。

Why

其实按上面的定义是不是感觉 visitor pattern 违反了将类本身的职责放在类中这个简单原则呢?在我看来是的,那为何出现了这种反原则的模式并且堂而皇之的成为了24种模式之一呢?其实这是因为语言自身的问题导致的。visitor pattern 的底层本质是 double dispatching, 而像Java 这种语言只支持single dispatching,而要实现 double dispatching 怎么办呢,就只能使用 visitor pattern这种笨拙的模式了。

How

现在我们有两种动物,定义如下:

public abstract class Animal{}
public class Dog extends Animal{}
public class Cat extends Animal{}

我们需要增加一个叫声的方法,由于猫狗的叫声不一样,我们需要将3个类都修改一下。

public abstract class Animal {public abstract void makeSound();
}
public class Dog extends Animal{public void makeSound() {System.out.println("wang wang");}
}
public class Cat extends Animal{public void makeSound(){System.out.println("miao miao");}
}

过了两天我们发现还需要增加一个eat 的方法,三个类又需要同步修改,违反了OCP原则,这时我们就可以使用Visitor Pattern,将变化提取出来, Animal的三个类保持不动。

public abstract class Animal{}
public class Dog extends Animal{}
public class Cat extends Animal{}
public abstract class AnimalVisitor {public abstract void visit(Animal animal);public abstract void visit(Dog dog);public abstract void visit(Cat cat);
}
public class MakeSoundVisitor extends AnimalVisitor{public void visit(Animal animal){System.out.println("animal sound")}public void visit(Dog dog){System.out.println("wang wang");}public void visit(Cat cat) {System.out.println("miao miao");}
}
public class EatVisitor extends AnimalVisitor {public void visit(Animal animal){System.out.println("animal eat");}public void visit(Dog dog){System.out.println("eat dog food");}public void visit(Cat cat){System.out.println("eat cat food");}
}

很美好,我们每当有什么操作需要添加的时候就新增一个继承了AnimalVisitor的类,由它来定义具体的行为。我们可以这样使用

Dog dog = new Dog();
Cat cat = new Cat();EatVisitor eat = new EatVisitor();
eat.visit(dog);
eat.visit(cat);

但这存在一个问题,我们只能使用具体的Dog Cat 类,而不能使用父类Animal

Animal dog = new Dog();
eat.visit(dog);//animal eat

明明dog 是 Dog类型,调用却到了Animal上,就是因为Java不具备按运行时类型来做不同的函数调用,也就是上面所说的不支持double dispatching,才导致了这样的结果。

如何解决这个问题呢?Java是支持方法的动态调用的(single dispatching),我们可以根据这个来间接实现double dispatching,也就是由Animal 类族做一次转发。

public abstract class Animal{public void visit(AnimalVisitor visitor){visitor.visit(this);}
}
public class Dog extends Animal{public void visit(AnimalVisitor visitor){visitor.visit(this);}
}
public class Cat extends Animal{public void visit(AnimalVisitor visitor){visitor.visit(this);}
}

很多visitor 模式的例子对不同的类使用了不同的方法名,这里我们在每个子类中的代码与父类中的代码一样,但是this的含义是不一样的。

使用时我们就需要由Visitor 调用 Animal变成Animal 调用Visitor了。

EatVisitor eat = new EatVisitor();
Animal dog = new Dog();
dog.visit(eat);

compare

Visitor Patter 将子类中的实现全部拿到了Visitor中来做,如果熟悉函数式编程的人就会觉得这个模式很面熟。其实这就是函数式编程中强大的模式匹配的一部分,根据不同的子类选择的不同的函数而已。

summary

Visitor 模式使用的很稀少,很大一个原因是它的条件太苛刻,它要求被visit的类族是稳定的,但是做过需求的都知道类是不断变化的。网上也有很多人说visitor 模式是一个反模式,不应该使用。我们辩证地来看待,毕竟这是在语言限制的条件做出的不得已选择。

reference

  • visitor pattern
  • A little Java A little pattern
  • Double Dispatch
  • 解密“设计模式”

转载于:https://my.oschina.net/liufq/blog/2966453

Visitor Pattern相关推荐

  1. 设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern): 封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 主要将数据结构与数据操作分离,解决数据结构和操作 ...

  2. 二十四种设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern) 介绍 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 示例 有一个Message实体类,某些对 ...

  3. DP-访问者模式(Visitor Pattern)

    一. 访问者(Visitor)模式 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 问题提出 System.Collect ...

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

    訪问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式. 据<大话设计模式>中说算是最复杂也是最难以理解的一种模式了. 定义(源于GoF<De ...

  5. C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】

    一.引言 今天我们开始讲"行为型"设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获得任 ...

  6. java 访客模式,设计模式 - 访客模式( Visitor Pattern)

    设计模式 - 访客模式( Visitor Pattern) 在Visitor模式中,我们使用一个访问者类来更改元素类的执行算法. 通过这种方式,元素的执行算法可以随着访问者的变化而变化. 此模式属于行 ...

  7. java visitor_Java Visitor Pattern(访问者模式)

    在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法.通过这种方式,元素的执行算法可以随着访问者改变而改变.这种类型的设计模式属于行为型模式.根据模式,元 ...

  8. 访问者(Visitor Pattern )模式

    主要用途是对聚集采取某种操作,统一执行. 访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化. 比如雇员对象,我们先只有名称.年龄 ...

  9. 40访问者模式(Visitor Pattern)

    类层次结构的变化:     类层次结构中可能经常由于引入新的操作,从而将类型变得脆弱...                             动机:     在软件构建过程中,由于需求的改变,某 ...

  10. Net设计模式实例之访问者模式(Visitor Pattern)

    一.访问者模式简介(Brief Introduction) 表示一个作用于某对象结构中的元素操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作,它把数据结构和作用于结构上的操作之间的耦 ...

最新文章

  1. linux线程有什么用,在linux下查看一个进程它有多少个线程是用什么命令?
  2. kafka 异步发送阻塞_Kafka学习一
  3. 《我想进大厂》之mysql夺命连环13问
  4. vue render
  5. 《UNIX编程环境》——5.6 zap:使用名字终止进程
  6. 路由器与计算机IP配置,电脑的IP地址和DNS等参数如何设置
  7. 《深入理解分布式事务》第八章 TCC 分布式事务原理
  8. Timeline的Clip编辑模式总结
  9. linux中程序包管理方式出现的原由(转载)
  10. Java中重写与重载的区别
  11. 使用STL标准模板库实现的个人通讯录
  12. VS2010 常用快捷键
  13. 关于intel六代/七代CPU安装win7系统解决USB3.0驱动的镜像文件
  14. API接口测试用例设计
  15. oracle cogs 科目,CFA一级财报科目:现金流量表详情介绍!
  16. 频繁gc是什么意思_一次解决jvm GC过于频繁的经历
  17. python flask豆瓣微信小程序案例
  18. 微服务开发中的数据架构设计 1
  19. 线性函数,C语言方式实现
  20. JAVA毕设项目家庭记账系统(java+VUE+Mybatis+Maven+Mysql)

热门文章

  1. 极客大学架构师训练营 框架开发 模式与重构 JUnit、Spring、Hive核心源码解析 第6课 听课总结
  2. 大整数的代数运算_高等代数教学笔记2:多项式I
  3. 推流式搅拌器选型功率计算方法_QSJ-1000
  4. 459.重复的子字符串
  5. 逻辑斯蒂回归和感知机模型、支持向量机模型对比
  6. efsframe java_EfsFrame(java开发框架)
  7. 凸优化有关的数值线性代数知识 作业题
  8. effective Java chapter 2创建和销毁对象
  9. linux 文件压缩与解压
  10. rbf java_RBF网络