访问者模式讨论篇:java的动态绑定与双分派

java的动态绑定

        所谓的动态绑定就是指程执行期间(而不是在编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。java继承体系中的覆盖就是动态绑定的,看一下如下的代码:

class Father {
    public void method(){
        System.out.println("This is Father's method");
    }
}

class Son1 extends Father{
    public void method(){
        System.out.println("This is Son1's method");
    }
}

class Son2 extends Father{
    public void method(){
        System.out.println("This is Son2's method");
    }
}

public class Test {
    public static void main(String[] args){
        Father s1 = new Son1();
        s1.method();

        Father s2 = new Son2();
        s2.method();
    }
}

运行结果如下:

This is Son1's method

This is Son2's method

       通过运行结果可以看到,尽管我们引用的类型是Father类型的,但是运行时却是调用的它实际类型(也就是Son1和Son2)的方法,这就是动态绑定。在java语言中,继承中的覆盖就是是动态绑定的,当我们用父类引用实例化子类时,会根据引用的实际类型调用相应的方法。

java的静态绑定

       相对于动态绑定,静态绑定就是指在编译期就已经确定执行哪一个方法。在java中,方法的重载(方法名相同而参数不同)就是静态绑定的。重载时,根据对象的表面类型决定调用哪个方法。看一下代码:

class Father {}
class Son1 extends Father{}
class Son2 extends Father{}

class Execute {
    public void method(Father father){
        System.out.println("This is Father's method");
    }

    public void method(Son1 son){
        System.out.println("This is Son1's method");
    }

    public void method(Son2 son){
        System.out.println("This is Son2's method");
    }
}

public class Test {
    public static void main(String[] args){
        Father father = new Father();
        Father s1 = new Son1();
        Father s2 = new Son2();

        Execute exe = new Execute();
        exe.method(father);
        exe.method(s1);
        exe.method(s2);
    }
}

运行结果如下:

This is Father's method

This is Father's method

This is Father's method

  在这里,程序在编译的时候就已经确定使用method(Father father)方法了,不管我们在运行的时候传入的实际类型是什么,它永远都只会执行method(Father father)这个方法。也就是说,java的重载是静态绑定的。

instanceof操作符与转型

       有时候,我们希望在使用重载的时候,程序能够根据传入参数的实际类型动态地调用相应的方法,也就是说,我们希望java的重载是动态的,而不是静态的。但是由于java的重载不是动态绑定,我们只能通过程序来人为的判断,我们一般会使用instanceof操作符来进行类型的判断。我们要对method(Father father)进行修改,在方法体中判断运行期间的实际类型,修改后的method(Father father)方法如下:

public void method(Father father){
    if(father instanceof Son1){
        method((Son1)father);
    }else if(father instanceof Son2){
        method((Son2)father);
    }else if(father instanceof Father){
        System.out.println("This is Father's method");
    }
}

   请注意,我们必须把判断是否是父类的条件(也就是判断是否为Father类的条件)放到最后,否则将一律会被判断为Father类,达不到我们动态判断的目的。修改代码后,程序就可以动态地根据参数的实际类型来调用相应的方法了。运行结果如下:

This is Father's method

This is Son1's method

This is Son2's method

  但是这种实现方式有一个明显的缺点,它是伪动态的,仍然需要我们来通过程序来判断类型。假如Father有100个子类的话,还是这样来实现显然是不合适的。必须通过其他更好的方式实现才行,我们可以使用双分派方式来实现动态绑定。

用双分派实现动态绑定

        首先,什么是双分派?可以理解为执行一个方法,到实际的执行,需要分派2次。

  我们可以看一下java双分派的特点:首先要有一个访问类B,类B提供一个showA(A a) 方法,在方法中,调用类A的method1方法,然后类A的method2方法中调用类B的showA方法并将自己作为参数传给showA。双分派的核心就是这个this对象。说到这里,我们已经明白双分派是怎么回事了,但是它有什么效果呢?就是可以实现方法的动态绑定,我们可以对上面的程序进行修改,代码如下: 

class Father {
    public void accept(Execute exe){
        exe.method(this);
    }
}
class Son1 extends Father{
    public void accept(Execute exe){
        exe.method(this);
    }
}
class Son2 extends Father{
    public void accept(Execute exe){
        exe.method(this);
    }
}

class Execute {
    public void method(Father father){
        System.out.println("This is Father's method");
    }

    public void method(Son1 son){
        System.out.println("This is Son1's method");
    }

    public void method(Son2 son){
        System.out.println("This is Son2's method");
    }
}

public class Test {
    public static void main(String[] args){
        Father father = new Father();
        Father s1 = new Son1();
        Father s2 = new Son2();

        Execute exe = new Execute();
        father.accept(exe);
        s1.accept(exe);
        s2.accept(exe);
    }
}

  可以看到我们修改的地方,在Father,Son1,Son2中分别加入一个双分派的方法。调用的时候,原本是调用Execute的method方法,现在改为调用Father的accept方法。运行结果如下:

This is Father's method

This is Son1's method

This is Son2's method

        运行结果符合我们的预期,实现了动态绑定。双分派实现动态绑定的本质,就是在重载方法委派的前面加上了继承体系中覆盖的环节,由于覆盖是动态的,所以重载就是动态的了,与使用instanceof操作符的效果是一样的(用instanceof操作符可以实现重载方法动态绑定的原因也是因为instanceof操作符是动态的)。但是与使用instanceof操作符实现动态绑定相比,双分派方式的可扩展性要好的多。

 

 转自CSDN :http://blog.csdn.net/zhengzhb/article/details/7496949

时间: 2024-09-09 06:11:52

访问者模式讨论篇:java的动态绑定与双分派的相关文章

18、Python与设计模式--访问者模式

一.药房业务系统 假设一个药房,有一些大夫,一个药品划价员和一个药房管理员,它们通过一个药房管理系统组织工作流程.大夫开出药方后,药品划价员确定药品是否正常,价格是否正确:通过后药房管理员进行开药处理.该系统可以如何实现?最简单的想法,是分别用一个一个if-else-把划价员处理流程和药房管理流程实现,这样做的问题在于,扩展性不强,而且单一性不强,一旦有新药的加入或者划价流程.开药流程有些变动,会牵扯比较多的改动.今天介绍一种解决这类问题的模式:访问者模式.首先,构造药品类和工作人员类: cla

设计模式之禅之设计模式-访问者模式

一:访问者模式定义        --->封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 二:访问者模式角色● Visitor--抽象访问者        抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的.● ConcreteVisitor--具体访问者        它影响访问者访问到一个类后该怎么干,要做什么事情.● Element--抽象元素        接口或者抽象类,声

深入浅出Java的访问者模式

一.引子 对于系统中一个已经完成的类层次结构,我们已经给它提供了满足需求的接口.但是面对新增加的需求,我们应该怎么做呢?如果这是为数不多的几次变动,而且你不用为了一个需求的调整而将整个类层次结构统统地修改一遍,那么直接在原有类层次结构上修改也许是个 不错 的主意. 但是往往我们遇到的却是:这样的需求变动也许会不停的发生:更重要的是需求的任何变动可能都要让你将整个类层次结构修改个底朝天--.这种类似的操作分布在不同的类里面,不是一个好现象,我们要对这个结构重构一下了. 那么,访问者模式也许是你很好

Java设计模式(二十一)----访问者模式

访问者模式 一.概述 1.定义 2.分派的概念 3.分派的类型 4.双重分派 二.结构 三.具体案例 一.概述 1.定义 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 2.分派的概念 变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type):而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type).比如: List list = n

详解Java设计模式编程中的访问者模式_java

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作.类型:行为类模式类图: 例子:例如,思考一下添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用.现在,计算逻辑即为计算这些不同类型商品的价格.或者说通过访问者模式我们把此逻辑转移到了另外一个类上面.让我们实现这个访问者模式的例子. 为了实现访问者模式,最先需要做的是创建能够被添加到购物车中代表不同类型商品(itemElement)的类. ItemElement.ja

举例讲解设计模式中的访问者模式在Java编程中的运用_java

访问者(Visitor)模式:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作.访问者模式的结构图如下: 通过上图可以看到他有如下角色:抽象访问者(Visitor)角色:定义接口,声明一个或多个访问操作. 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作. 抽象元素(Visitable)角色:声明一个接受操作,接受一个访问者对象作为一个参数. 具体元素结点(Concrete

Java设计模式--访问者模式

访问者模式(别名:虚拟构造) 表示一个作用于某对象结构中的各个元素的操作.它可以在不改变各个元素的类的前提下定义作用于这些元素的新操作. Visitor Pattern Represent an operation to be preformed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements o

JAVA设计模式之访问者模式详解_java

在阎宏博士的<JAVA与模式>一书中开头是这样描述访问者(Visitor)模式的: 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 分派的概念 变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type):而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type).比如: 复制代码 代码如下: List lis

java中的访问者模式 – 例子辅导

原文链接 作者:Pankaj Kumar 译者:f0tlo <1357654289@qq.com> 访问者模式是一种行为设计模式.访问者模式被用在针对一组相同类型对象的操作.优点是,可以把针对此对象的操作逻辑转移到另外一个类上. 例如,思考一下添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用.现在,计算逻辑即为计算这些不同类型商品的价格.或者说通过访问者模式我们把此逻辑转移到了另外一个类上面.让我们实现这个访问者模式的例子. 为了实现访问者模式,最先需要做的是创建能够