实现不应该调用的派生方法的最佳实践

时间:2015-02-16 09:51:31

标签: java inheritance object-oriented-analysis

我有一个JAVA类A,它有一个方法foo

abstract class A {
  abstract void foo();
}

我还有一个派生类A - MutableA。 MutableA是一个单例对象,表示不需要更新,这对重用代码流很有用。 永远不应该在MutableA上调用foo()。 实现这一目标的最佳方法是什么:

  1. 抛出不支持的异常
  2. 什么都不做(空实施)
  3. 这是一个糟糕的设计。
  4. 有人可以推荐一下这种情况下的最佳做法吗?

6 个答案:

答案 0 :(得分:2)

因为你说"不需要更新" ,所以似乎是一个空的实现方式。如果我这样做:

A someA = createA();
someA.foo();           // make sure it's "foo"ed

我不知道我是否回来了MutableA,所以我打电话给foo只是为了确定。

如果禁止foo上拨打MutableA,我会选择UnsupportedOperationException或重新考虑设计。也许你可以将A包装在AHandler中,该foo知道何时以及如何在它所包含的实例上调用{{1}}。

答案 1 :(得分:2)

我会考虑重新考虑设计。

在超类中使用抽象方法意味着子类应该实现该方法。除非您计划使用更大的层次结构,否则您应该考虑将foo方法降低到更接近实现的层次结构中。

如果您打算保留foo方法的位置,我也会将MutableA抽象化。

答案 2 :(得分:2)

你应该考虑看一下Liskov替代原理,这是良好设计的基本SOLID原则之一。

该原则规定派生对象的行为不应与其父母不同。违反Liskov原则的一个常见例子是从椭圆中推导出一个圆。这在数学上是完全合理的,声音被认为是糟糕的设计,因为从椭圆得到的圆(例如)仍会暴露方法来设置宽度和高度,但在某些情况下它会表现得很奇怪。请考虑以下

Something FooBar (Ellipse e)
{ 
    // do something with e
}

如果我们不知道调用者通过Circle而不是Ellipse并且我们设置了宽度和高度,我们的结果可能与我们预期的不同,因为Circle忽略了SetHeight或者它设置了SetWidth上的宽度bot和SetHeight。无论哪种方式,如果我们期望在Ellipse上操作,这种行为是出乎意料的。因此Liskov替代原则。

答案 3 :(得分:1)

这取决于该方法的用途。 您列出的所有替代品几乎都是好的。

顺便说一句,如果你抛出一个UnsupportedOperation异常,你就知道不应该使用这个方法。使用例外始终是"消息"偏离"正常",所以你要定义与A.foo()的基本实现相关的事情,但是你也要用它来分解这个实现。子类。

如果你使用一个空的实现,你可以在一个hypotetical流程中使子类更加可用,而不会与过去(超类A)分开,所以你可能不知道使用子类在你想要的每一种环境中。

在最后的分析中,你说MutableA是单身,所以我认为你会在特定的环境中使用它,特别注意它:所以我会采用"异常&# 34;溶液

答案 4 :(得分:1)

我使用这样的东西:

public abstract class ReadableA {
}

public abstract class A extends ReadableA{
  abstract void foo();
}

public class MutableA extends ReadableA {
}

代码中您希望收到A的所有位置,请改为使用ReadableA,除非您特别想要致电foo()。然后将A放入方法签名中。如果您想收到MutableA,请写一个MutableA签名。

示例:

public class UsageOfA {
  public void bar(ReadableA a) {
    // Can use both A and MutableA but a.foo() cannot be invoked.
  }
  public void bar(A a) {
    a.foo();
  }
  public void bar(MutableA a) {
    // a.foo() cannot be invoked.
  }
}

答案 5 :(得分:1)

我认为抛出UnsupportedOperationException是正确的选择。假设您有3个课程延长A

class X extends A{
//foo allowed here
}
class Y extends A{
//foo allowed here
}
class Z extends A{
//foo allowed here
}
class MutableA extends A{
//foo NOT allowed here
}

现在从设计角度来看,X,Y,Z and MutableA应该以{em>一致的方式表现foo()。我不鼓励引入另一个类层次结构,只是为了使MutableA foofree 。一个简单的灵魂就是抛出UnsupportedOperationException并让调用者知道调用对象不能支持该方法。另一方面,实现仍然有效,坦率地说,从设计角度来看并不合适,因为它是 >仍然是来自调用对象的有效调用

PS:我也会考虑重新思考设计。任何可用但不应该使用的方法都不是好设计的一部分。