派生类中引入的公共接口

本文关键字:接口 派生 | 更新日期: 2023-09-27 18:27:59

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

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()
    {            
    }
}

我将派生对象混合在一个集合中(例如列表),因为有时我必须对集合中的所有对象调用通用(继承)方法,但有时我只想对D2对象调用Bar()

        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对象上调用它将没有意义(D1.Bar()的实现将包含什么?)。界面和组合也没有帮助。我觉得这是一种非常常见的情况,我想知道这种情况下的最佳做法是什么?如何避免下转换,但允许调用特定于派生类型的公共方法

派生类中引入的公共接口

在我看来,根据您的描述,"check and downstast"实际上是恰当的:

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

现在这是一个有点奇怪的需求,但如果的需求,我认为以直接的方式实现它是合理的,而不是为基类上没有意义的操作添加无操作实现。

然而,我的做法略有不同:

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

现在这正是你的意思:)

看起来D2向B添加的行为比最初定义的要多。这表明违反了单一责任原则(D2做了不止一件事)。向下转换还表明将D1和D2保持在同一列表中不一定是有意义的。所以,也许"IS A"关系在这里不合适?我会尝试切换到组合,并为D1和D2使用一组精确定义的接口,参考接口分离原则。那么,D1和D2可能会混合在一个列表中,但前提是你对一个特定的行为(接口)感兴趣,而对于另一个接口,你的列表中只有D2(既不知道,也不关心)。