什么是易于理解*坏*使用继承的例子?

时间:2010-08-05 15:36:29

标签: language-agnostic inheritance

我正在寻找使用继承的糟糕示例。我不是很有创意,所以这是我能想到的最好的:

class Car : public Engine {}

汽车有引​​擎,但它不是引擎。

这可能有助于解释这个概念,但我相信还有更多的说明性例子?

4 个答案:

答案 0 :(得分:5)

“经典”示例; - ):

public class Stack extends Vector { 
    ...
}

堆栈不是矢量。

如果Stack扩展了Vector,你可以在每个给定的索引处插入/删除,而你应该只允许通过推/弹来添加/删除元素。

答案 1 :(得分:4)

几乎使用任何使用继承的示例,而不考虑基类的行为

一个典型的例子是SquareRectangle之间的关系。当然,在数学中,正方形是一种矩形。但是,在软件设计中,正方形的行为不像矩形:

public class Rectangle 
{
    public virtual int Width  { get; set; }
    public virtual int Height { get; set; }
}

public class Square : Rectangle
{
    public override int Width
    {
        get { return base.Width; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }

    public override int Height
    {
        get { return base.Height; }
        set
        {
            base.Height= value;
            base.Width = value;
        }
    }
}

如果另一个类Client需要Rectangle但得到Square,则Client会中断,因为它希望其Rectangle拥有Width 1}}和Height互不影响。

答案 2 :(得分:1)

继承非常有用,但也打破了封装。这意味着您的子类依赖于超类的实现细节;如果超类发生更改,您的子类可能会中断。这是Java中的一个例子,来自Josh Bloch的Effective Java:

public class InstrumentedHashSet<E> extends HashSet<E> {

   // number of attempted element insertions
   private int addCount = 0;

   public int getAddCount() {
      return addCount;
   }

   @Override public boolean addAll<Collection<? extends E> c) {
       addCount += c.size();
       return super.addAll(c);
   }
}

问题是HashSet的addAll()方法在内部使用了它的add()方法,但没有记录它。所以如果你试试

InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));

你得到的数字是6而不是3.在这个特殊情况下,这不是很有害,但如果你要添加一个大型集合或进行其他操作,它可能是。

因此,具体类通常不是继承的好主意,除非它们被设计为具有子类。

答案 3 :(得分:0)

这已经讨论多年了,你会发现很多材料/谈话在谷歌上引用这个问题。

public class Square extends Rectangle { 
    ...
}

也许不是很令人惊讶,广场不应该从矩形继承。