0

昨天我问了这个问题,@JB Nizet 发布的解决方案效果很好。然而,这个答案以及其他一些答案/评论让我完全想到了一个不同的方向。

本质上,我有以下课程:

  • Load
  • HttpLoad extends Load
  • Target
  • HttpTarget extends Target
  • Controller

Controller工作是Target::fire()a Load,并不关心哪个Target在触发哪个Load

// Inside Controller.java
Target target = getTarget();
Load load = getLoad();

target.fire(load);

但是,有一天我可能会写 a FtpLoad extends Load,但我不希望能够在 aFtpLoad上触发 a HttpTarget。所以上面提到的问题的本质是我该怎么做,答案是泛型

但是,正如回答者指出的那样,这种解决方案违反了 Liksov 替换原则。其他回答者/评论者似乎表示我所做的不一定是好的 OOP 实践。

所以现在我要问:我如何公开一个 API,以便Controller可以Load- 并且 -Target不可知,但仍然强制在正确的类型Load上触发正确的子类Target,所有这些都不会违反 Liskov Substitution?

而且,如果这是不可能的(不违反 Liskov),那么解决此类问题的正常方法是什么?提前致谢!

4

5 回答 5

1

如果HttpTarget.fire允许任何Load作为参数,它的工作就是检查它是否可以firethis Load。因此,要么盲目地Controller调用,并检查给定的目标是否可以触发那种(with ),要么在每个实现此检查并由.firefireLoadinstanceofcanFiretargetController

于 2012-09-21T23:05:27.777 回答
1

这里的打字问题是 thatHttpTarget不是 Liskov 的子类型Target,因为在语义上它试图加强Target#fire(Load)要求Loadbe的先决条件HttpLoad

这可以通过声明Target#fire(Load) throws IncompatibleLoadException并拥有一个总是抛出的默认实现来轻松修复,强制处理可以传入Controller不匹配的事实。Load

于 2012-09-21T23:35:04.470 回答
0

最好是实现抽象类或接口并使用前面提到的instanceof。

使用抽象类:

public abstract class TargetLoad {
    public abstract void fire(TargetLoad i);
}

public class Load extends TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Target) return;
        // do fire stuff
    }
}

public class Target extends TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Load) return;
        // do fire stuff
    }
}

带接口:

public interface TargetLoad {
    public void fire(TargetLoad i);
}

public class Load implements TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Target) return;
        // do fire stuff
    }
}

public class Target implements TargetLoad {
    @Override
    public void fire(TargetLoad i) {
        if (i instanceof Load) return;
        // do fire stuff
    }
}

在您的控制器中,您将对象称为 TargetLoad

TargetLoad target = getTarget();
TargetLoad load = getLoad();

target.fire(load);
load.fire(target);
load.fire(load);     //this will do nothing
target.fire(target); //this will do nothing
于 2012-09-21T23:19:35.530 回答
0

简单的方法是检查您的代码以确保类匹配。您可以使用instanceof关键字来检查它是否是正确的类。

于 2012-09-21T23:03:36.497 回答
0

我强烈不同意建议使用的大量答案instanceof。编写良好的 OOP 代码很少需要使用instanceof,而使用instanceof通常会使您的代码笨拙且难以维护。作为一般规则,instanceof尽可能避免。

您提到的上一个问题提供了使用泛型的解决方案。我不确定您是否将泛型代码排除在您的问题之外;回到你的通用代码。现在,将以下方法添加到您的驱动程序中。

private <L extends Load> void runSuite(TestSuite<L> suite) {
  Target<L> target = testSuite.getTarget();
  L load = testSuite.getLoad();
  target.fire(load);
}
于 2012-09-21T23:42:32.587 回答