java - 这是什么奇特之处?为什么我应该选择像访客设计模式这样的双重调度解决方案?

标签 java oop 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帐户代码”部分。

问题出在哪里?

最佳答案

简短回答:Java 没有运行时参数多态性(运行时根据参数类型选择方法)。

编译器将在对象上多态地调用子类方法,因此 act.open()如果 actDematAccount,将调用 DematAccount 的实现。然而,Java 的多态性对参数不起作用,所以bank.open(act)永远会打电话open(SavingAccount)如果 actSavingAccount 类型的变量,无论其运行时类型如何。

编译器在调用站点知道的相关信息是 act 是一个 SavingAccount 并且 bank 有一个方法 open( SavingAccount) 作为最接近的逆变匹配:

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

您可以使用 instanceof 进行类型转换,并将 act 转换为子类来解决此问题,或者您可以在 Bank 内进行类型转换类。

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

这有点丑陋,意味着将此代码耦合到各种帐户并在每次更改时更改它。

Bank操作系统中更好地改变它,因为Bank已经承担了了解所有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();
    }
}

在这种情况下,Bank 仅在控制台输出方面有所不同,您可以轻松地将控制台输出移至 SavingAccountDematAccount 并删除 >从银行打开(DematAccount)

关于java - 这是什么奇特之处?为什么我应该选择像访客设计模式这样的双重调度解决方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33846093/

相关文章:

java - 'Class<?>' 和 'Object' 作为方法参数之间的区别

java - 如何检查对象是否实现了接口(interface)?

java - 不允许同一玩家同时担任游戏中的两个玩家

java - Google Cloud Endpoints 自定义异常

java - AJAX 请求中止时停止 Redshift 上的 SQL 查询的替代方法

c++ - 从父类(super class)对象数组调用子类方法

javascript - Async/Await 函数永远不会通过 Dispatch 解决

jQuery 调度事件?如何

ios - 当我使用dispatch_apply时在模拟器中崩溃但iPhone

java - 如何配置 "overflow"的网格线