区分 class 类型以进行不同处理的最佳方法

Best way to differentiate between class types for different handling

我想知道使用以下每种方法区分主父 class 的子 class 并以不同方式处理它们的优点/缺点是什么。我知道这是非常基本的,但我无法在任何地方找到这些方式之间的完整比较。

例如: - 我有一个 Payment 超级抽象 class 和两个扩展 classes OneTimePaymentSubscription - 我有一个方法 switchPaymentState 应该以不同的方式处理这些类型中的每一个

那么,哪条路最好(或完全不同?),为什么?

编辑: 我需要根据 class 类型执行的操作不是对 class 本身的操作,我需要从付款中获取一些数据并通过其他服务发送,因此解决方案如在内部实现此功能classes 并调用它而不考虑类型,不幸的是在这种情况下无济于事。谢谢!

最模块化的方法是使用覆盖。

您将有一个 switchPaymentState 方法,它接受基本类型 - Payment - 并调用 Payment class 中的方法来进行处理。可以在付款的每个子 class 中覆盖该方法。

public void switchPaymentState(Payment payment)
{
    payment.handlePayment();
}

您的 switchPaymentState 方法不必知道付款的哪个子 class 存在,并且如果您添加新的子 class 它也不必更改明天就是了。

你的选项 3 在很多情况下都不起作用,因为重载是在编译时而不是 运行 时解决的。如果你引用的类型是Payment,就不能使用重载。

在面向对象设计中,使用重写方法就是"cleanest"方法。但是,它的缺点是相似的功能会分布在多个 classes 上,而在 switch 和 instanceof 解决方案中,一切都在一起。

提供两全其美的替代方案是所谓的访客模式。您创建了一个接口 PaymentVisitor,每个 class 您想要一个方法的句柄,如下所示:

interface PaymentVisitor {
    void visitOneTimePayment(OneTimePayment payment);
    void visitSubscription(Subscription payment);
}

然后在你抽象superclass你添加一个方法访问:

abstract class Payment {
    ...
    abstract void callVisitor(PaymentVisitor visitor);
}

您在所有子class中实施如下:

class OneTimePayment {
    ...
    @Override void callVisitor(PaymentVisitor visitor) {
        visitor.handleOneTimePayment(this);
    }
}

class Subscription {
    ...
    @Override void callVisitor(PaymentVisitor visitor) {
        visitor.handleSubscription(this);
    }
}

现在,在所有情况下你会写类似(伪Java)的东西:

switch (type of x) {
    case OneTimePayment:
         // Code
         break;
     case Subscription:
         // Code
         break;
}

您现在可以干净且类型安全地编写:

x.callVisitor(new PaymentVisitor() {
    @Override void handleOneTimePayment(OneTimePayment payment) {
        // Code
    }
    @Override void handleSubscription(Subscription payment) {
        // Code
    }
});

另请注意,访问者是在内部 class 中实现的,因此您仍然可以访问方法主体中定义的所有(有效)最终变量。

我认为 switch 有点反模式,不管你怎么做。更标准的 OO 方法是在两个子 class 中实现相同的方法,并让每个 class 适当地管理事物。也就是说

abstract class Payment {
    abstract void processPayment(BigDecimal amount);
    abstract void processRefund...
} 

class OneTimePayment extends Payment {
    void processPayment(BigDecimal amount){... }

    void processRefund...
}

等等

此外,除非您在 super class 中重复使用大量代码,否则请考虑基于接口的实现而不是 subclassing。