这有什么特点?为什么我应该选择像访客设计模式这样的双重调度解决方案?

问题描述 投票:0回答:1

您好,我有一个基本的代码特性问题,如下所示。当我更改代码时,我会得到奇怪的输出。下面的程序给出了正确的输出,因为我们知道 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 oop dispatch
1个回答
2
投票

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

编译器将在对象上多态地调用子类方法,因此如果

act
DematAccount,则 act.open() 将调用 DematAccount 的实现。然而,Java 的多态性不适用于参数,因此,如果
act
SavingAccount
类型的变量,无论其运行时类型如何,bank.open(act) 将始终调用 open(SavingAccount)

编译器在调用站点知道的相关信息是 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 os 中更改它会更好,因为 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,并从Bank中删除open(DematAccount)

© www.soinside.com 2019 - 2024. All rights reserved.