派生类中引入的公共接口

时间:2013-08-16 13:42:21

标签: c# oop inheritance downcast

两个类D1D2派生自抽象基类B。它们中的每一个都共享在B中声明的公共公共接口,但每个接口都可能有自己的特定公共接口(例如D2具有D2.Bar(),这仅对D2个对象有意义):

public abstract class B
{
    public int N { get; set; }
    public abstract void Foo();
}

public class D1 : B
{
    public override void Foo()
    {            
    }
}

public class D2 : B
{
    public override void Foo()
    {
    }

    public void Bar()
    {            
    }
}

我将派生对象混合在一个集合中(例如列表),因为有时我必须在集合中的所有对象上调用常用(继承)方法,但有时我想在{{1}上调用Bar()仅对象:

D2

我觉得代码闻到了这里。向下倾斜是一个坏主意,根据类型检查做出决定是个坏主意。如果我将 var list = new List<B>(); list.Add(new D1()); list.Add(new D2()); foreach(var b in list) if(b is D2) (b as D2).Bar(); 移到基类,那么在Bar()个对象上调用它是没有意义的( D1的实现包含什么?)。界面和组合也没有帮助。我觉得这是一种非常普遍的情况,我想知道这种情况下的最佳做法是什么?如何避免向下转换但允许调用特定于派生类型的公共方法?

2 个答案:

答案 0 :(得分:5)

在我看来,实际上,根据您的描述,“检查和投降”是正好

  

有时我想只在D2对象上调用Bar():

现在这有点奇怪的要求,但如果 是一个要求,我认为以一种简单的方式实现它是合理的,而不是为没有的操作添加no-op实现在基类上有意义。

但是,我会稍微改变一下:

foreach (var d2 in list.OfType<D2>())
{
    d2.Bar();
}

现在这说明了你的意思:)

答案 1 :(得分:1)

似乎D2正在向B添加比最初定义的更多行为。这表明Single Responsibility Principle正在被侵犯(D2不止一件事)。垂头丧气也表明将D1和D2保持在同一个列表中并不一定有意义。那么,也许“IS A”关系在这里不合适?我尝试切换到合成并使用一组精确定义的D1和D2接口,参考Interface Segregation Principle。那么D1和D2可能会在一个列表中混合,但只有当你对一个特定的行为(接口)感兴趣时,对于另一个接口你才会在列表中只有D2(不知道它,也不关心它)。 / p>