0

好的,这已经发生在我身上很多次了,所以我不妨问问社区。我经常遇到一个问题,即决定将某物声明为实例还是作为 is-a 继承(并声明子类的实例)是否合适。

例如,

  public class BaseStation{
             public BaseStation( int x, int y ){
                    this.x = x;
                    this.y = y;
             }

             public void setX( int x ){ this.x = x; }
             public void setY( int y ){ this.y = y; }

             private int x;
             private int y;
    }

现在,如果staticBaseStationis-a不会改变并且is-a会改变,我不能在每次位置更改时将静态和动态BaseStationBaseStations声明为带有调用的单独对象吗?但是我觉得这样做违反了OO原则。(x,y)dynamicBaseStationBaseStation(x,y)dynamicBaseStationsetXsetY

所以基本上当感觉就像额外工作时,我如何决定是否使用继承?

4

3 回答 3

1

这取决于您如何定义类的合同。

a) 如果您指定BaseStation值可以更改(或者您没有指定它不能更改),您可以使用该类的两个实例。

b)如果您指定BaseStation值不能更改,那么您不仅不能将同一类的两个实例用于该用途,而且您甚至不能扩展BaseStation以获得您的DynamicBaseStation(因为子类会违反超类合同)。您可能需要设置一个通用接口。

您的合同越严格,类的可重用性就越低。而且,由于类的行为得到了更好的定义,您可以使用它的属性来简化使用类/避免错误(该a方法可以让您更改 a 的值StaticBase,该b方法迫使您使用另一个类,即最好的,兄弟姐妹)。

在这个具体的类中,我会在BaseStation不指定它不能移动的情况下进行定义,并创建一个StaticBaseStation细化父合同(但不与之相矛盾)但确定它不能改变其位置的类。通常,程序是在您通过继承(专业化)时增加限制。

无论如何,这又是一条经验法则。可能有其他动机迫使您以一种或另一种方式定义合同;重要的是在扩展课程时不要中断。

于 2013-05-07T23:56:55.420 回答
0

我认为接口在这种情况下更合适,因为派生StaticBaseStation不会使用任何超类方法,但是您可能希望能够在某些情况下使用任何一种类型。

例如,如果这些类共享一个接口,您可以编写接受该接口作为参数的方法,这将允许您对这两种类型重用这些方法。

于 2013-05-07T23:56:45.130 回答
0

当派生类都可以相互替换时,您可以使用继承......并且消费者在使用基类时不需要了解派生类。

您的示例违反了 Liskov 替换原则。如果在预期使用 StaticBaseStation 的上下文中使用 DynamicBaseStation,则可能会发生不好的事情(意外行为)。

在此处或直接在此处查看 Liskov 替换原则。

在任何情况下,只要有可能,我都倾向于组合而不是继承。继承会给你带来麻烦,因为组合可以——主要是——几乎没有什么害处,但仍然允许你更改抽象背后的实现细节。请参阅此问题/答案

于 2013-05-08T00:15:05.813 回答