这个特点是什么?我为什么要选择像访问者设计模式这样的Double Dispatch解决方案?

时间:2015-11-21 17:01:02

标签: java oop core dispatch

嗨,我有一个基本的代码特性问题,如下所示。当我更改代码时,我得到了特殊的输出。下面的程序给出了正确的输出,因为我们知道Java默认情况下不支持Double Dispatch。请求您查看以下代码并查看输出。之后我修改了代码并获得了奇怪的输出。

import java.util.ArrayList;
import java.util.List;

class SavingAccount {

}

class DematAccount extends SavingAccount {

}

class Bank {

    public void open(SavingAccount act ) {
        System.out.println("... Opening Saving Account ...");
    }

    public void open(DematAccount act ) {
        System.out.println("... Opening Demat Account ...");
    }
}

public class Test {
    public static void main(String[] args) {
        List<SavingAccount> actList = new ArrayList<SavingAccount>();

        Bank bank = new Bank();

        actList.add( new SavingAccount());
        actList.add( new DematAccount());

        for( SavingAccount act : actList ) {
            bank.open(act);
        }
    }
}

这里的输出如下。 ...打开储蓄帐户... ...开立储蓄账户......

现在让我修改代码并查看下面的输出。

import java.util.ArrayList;
import java.util.List;

class SavingAccount {

    public void open() {
        System.out.println("... Opened Saving Account Successfully ...");
    }

}

class DematAccount extends SavingAccount {

    public void open() {
        System.out.println("... Opened Demat Account Successfully ...");
    }
}

class Bank {

    public void open(SavingAccount act ) {
        System.out.println("... Opening Saving Account ...");
        act.open();
    }

    public void open(DematAccount act ) {
        System.out.println("... Opening Demat Account ...");
        act.open();
    }
}

public class Test {
    public static void main(String[] args) {
        List<SavingAccount> actList = new ArrayList<SavingAccount>();

        Bank bank = new Bank();

        actList.add( new SavingAccount());
        actList.add( new DematAccount());

        for( SavingAccount act : actList ) {
            bank.open(act);
        }
    }
}

这里的输出是 ...打开储蓄账户...... ...成功开立储蓄账户...... ...打开储蓄账户...... ...成功开设了Demat账户......

现在我的问题是我得到的结果是我期待的,为什么我应该去访问模式,在上面的代码中,即使它显示“保存帐户”,但它正确执行“Demat帐户代码”部分。 / p>

请解释一下,问题出在哪里? 在此先感谢。

1 个答案:

答案 0 :(得分:1)

简短回答:Java没有运行时参数多态(在运行时选择基于参数类型的方法)。

编译器将在对象上多态调用子类方法,因此如果 act act.open()将调用 DematAccount 的实现DematAccount 即可。但是,Java的多态性不适用于参数,因此如果 act SavingAccount 类型的变量,bank.open(act)将始终调用open(SavingAccount)它的运行时类型。

编译器在呼叫站点知道的相关事项是行为 SavingAccount 银行的方法是打开( SavingAccount)作为最接近的逆变匹配:

for(SavingAccount act : actList ) {
    bank.open(act);
}

您可以使用 instanceof 进行类型套管并将 act 强制转换为子类以解决此问题,或者您可以在银行中执行该类型套管上课。

for(SavingAccount act : actList ) {
    if (act instanceof DematAccount) {
        bank.open((DematAccount) act);
    } else {
        bank.open(act);
    }
}

这种丑陋并意味着将此代码与各种帐户相关联,并在每次更改时对其进行更改。

更改银行操作系统更好,因为银行已经承担了了解所有 SavingAccount 子类的责任。

class Bank {

    public void open(SavingAccount act ) {
        if (act instanceof DematAccount) {
            open((DematAccount) act);
        } else {
            System.out.println("... Opening Saving Account ...");
            act.open();
        }
    }

    public void open(DematAccount act ) {
        System.out.println("... Opening Demat Account ...");
        act.open();
    }
}

在这种情况下银行仅在控制台输出中有所不同,您可以轻松地将该控制台输出移至 SavingAccount DematAccount 并移除银行开启(DematAccount)