昨天我问了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),那么这样的问题的正常方法是什么?提前谢谢!
答案 0 :(得分:1)
如果HttpTarget.fire
允许任何Load
作为参数,那么检查它是fire
Load
是否可行。因此,Controller
盲目调用fire
,fire
检查给定目标是否可以触发Load
(instanceof
),或者包含实现此检查的每个canFire
中的函数target
由Controller
调用。
答案 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);
}