将方法的默认实现放在超类中,并在子类想要偏离它时重写它,还是应该保留超类方法抽象,并在许多子类中重复正常实现?
例如,我参与的一个项目有一个类,用于指定它应该停止的条件。抽象类如下:
public abstract class HaltingCondition{
public abstract boolean isFinished(State s);
}
一个简单的实现可能是:
public class AlwaysHaltingCondition extends HaltingCondition{
public boolean isFinished(State s){
return true;
}
}
我们对对象执行此操作的原因是我们可以任意将这些对象组合在一起。例如:
public class ConjunctionHaltingCondition extends HaltingCondition{
private Set<HaltingCondition> conditions;
public void isFinished(State s){
boolean finished = true;
Iterator<HaltingCondition> it = conditions.iterator();
while(it.hasNext()){
finished = finished && it.next().isFinished(s);
}
return finished;
}
}
但是,我们有一些停止条件需要通知事件已发生。例如:
public class HaltAfterAnyEventHaltingCondition extends HaltingCondition{
private boolean eventHasOccurred = false;
public void eventHasOccurred(Event e){
eventHasOccurred = true;
}
public boolean isFinished(State s){
return eventHasOccurred;
}
}
eventHasOccurred(Event e)
我们应该如何在抽象超类中最好地表示?大多数子类可以有这个方法的无操作实现(例如AlwaysHaltingCondition
),而有些需要重要的实现才能正确操作(例如HaltAfterAnyEventHaltingCondition
),而其他子类不需要对消息做任何事情,但必须将其传递给它们的下属,以便它们将正常运行(例如ConjunctionHaltingCondition
)。
我们可以有一个默认实现,这将减少代码重复,但如果没有覆盖它会导致一些子类编译但不能正确运行,或者我们可以将方法声明为抽象,这将要求每个子类的作者想想他们提供的实现,尽管十分之九是无操作实现。这些策略的其他优点和缺点是什么?一个比另一个好吗?