OOP:如何编写类的家庭一起工作?

时间:2012-09-21 22:51:29

标签: java oop generics

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

基本上,我有以下几个类:

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

Controller的工作是Target::fire()Load,而不关心Target解雇了哪个Load

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

target.fire(load);

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

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

所以现在我问:如何公开API以便Controller可以Load - 和Target - 不可知,但仍然强制执行Load子类是在适当的Target类型上触发的,所有这些都没有违反Liskov替换?

而且,如果这是不可能的(没有违反Liskov),那么这样的问题的正常方法是什么?提前谢谢!

5 个答案:

答案 0 :(得分:1)

如果HttpTarget.fire允许任何Load作为参数,那么检查它是fire Load是否可行。因此,Controller盲目调用firefire检查给定目标是否可以触发Loadinstanceof),或者包含实现此检查的每个canFire中的函数targetController调用。

答案 1 :(得分:1)

此处的输入问题是 HttpTarget不是Target 的Liskov子类型,因为在语义上它正试图加强前提条件Target#fire(Load)要求Load成为HttpLoad

这可以通过声明Target#fire(Load) throws IncompatibleLoadException并且具有始终抛出的默认实现来轻松修复,迫使Controller处理可以传入不匹配Load的事实。

答案 2 :(得分:0)

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

答案 3 :(得分: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
    }
}

在Controller中,您将对象称为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

答案 4 :(得分: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);
}