继承,还是我应该使用组合?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了继承,还是我应该使用组合?相关的知识,希望对你有一定的参考价值。

让我们说我有一堂课

public class Transfer 
{
    prop1
    prop2
    ....
    public List<SubTransfer> SubTransfers { get; set; }
}

我从连接数据库的函数得到的

现在我希望有一个类,它可以为Transfer和每个SubTransfer添加一个状态。

一个问题是我应该在这里使用继承吗?还是作文?

我认为继承,所以我试图做这样的事情:

public ExtendedSubTransfer : SubTransfer
{
    public StatusEnum Status { get; set; }
}

public ExtendedTransfer : Transfer
{
    public StatusEnum Status { get; set;}
}

我的问题是我不知道如何做到这一点,我将获得使用扩展传输时的扩展SubTransfer列表。

我知道我可以使用关键字new覆盖SubTransfers,如下所示:

public new List<ExtendedSubTransfers> SubTransfers {get; set;}

它是“合法的”吗?或者你有其他建议吗?

谢谢您的帮助!

答案

它会编译,但它可能不会做你想要的。请记住,List<ExtendedSubTransfer>不会扩展List<SubTransfer>。例如,如果您有任何使用基类的操作,您将无法获得所需的操作。为了演示,让我们假装基类具有ID并且您想要打印ID。

public void PrintIds()
{
    ExtendedTransfer extendedTransfer = _database.GetExtendedTransfer(...);
    PrintSubTransferIds(extendedTransfer);
}

private PrintSubTransferIds(Transfer transfer)
{
    foreach(var subTransfer in transfer.SubTransfers)
    {
        Console.WriteLine(subTransfer.Id);
    }
}

除非您在从数据库加载项目时执行一些非常奇怪的操作,否则上述方法将无效。例如,如果您的加载代码看起来像......

public GetExtendedTransfer(...)
{
    ExtendedTransfer result = new ExtendedTransfer();
    List<ExtendedSubTransfer> subTransfers = _connection.QueryForSubTransfers(...);
    result.SubTransfers = subTransfers;
    return result;
}

然后它将无法正常工作。它不会打印任何子转移ID,因为transfer.SubTransfers将是一个空列表。相反,当你从数据库加载时,你必须做一些奇怪的事情......

public GetExtendedTransfer(...)
{
    ExtendedTransfer result = new ExtendedTransfer();
    List<ExtendedSubTransfer> subTransfers = _connection.QueryForSubTransfers(...);
    result.SubTransfers = subTransfers;
    Transfer subtypedResult = result;
    subtypedResult.SubTransfers = subTransfers.Cast<SubTransfer>();
    return result;
}

此外,以下情况将是编译时错误:

public void PrintIds()
{
    ExtendedTransfer extendedTransfer = _database.GetExtendedTransfer(...);
    PrintSubTransferIds(extendedTransfer.SubTransfers);
}

private PrintSubTransferIds(List<SubTransfer> subTransfers)
{
    foreach(var subTransfer in subTransfers)
    {
        Console.WriteLine(subTransfer.Id);
    }
}

这将无法编译,因为extendedTransfer.SubTransfers的类型为List<ExtendedSubTransfer>,无法分配给List<SubTransfer>

更新:那你该怎么办?

C#(4.X及以上)允许在covariance上使用certain interfaces,例如IReadOnlyList(C#4.5及以上)。这样你就可以......

public class Transfer 
{
    public virtual IReadOnlyList<SubTransfer> SubTransfers { get; private set; }
    public void SetSubTransfers(List<SubTransfer> subTransfers)
    {
        SubTransfers = subTransfers;
    }
}

public class ExtendedTransfer
{
    private List<ExtendedSubTransfer> _subTransfers;

    public override IReadOnlyList<SubTransfer> SubTransfers
    {
        get { return _subTransfers; }
    }

    public void SetSubTransfers(List<ExtendedSubTransfer> subTransfers)
    {
        _subTransfers = subTransfers;
    }
}

这将是我解决问题的最佳尝试。但是,您没有提到如何从数据库中获取实体。我不认为EntityFramework默认会对这种场地安排感到非常满意。

以上是关于继承,还是我应该使用组合?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的继承与组合(转载)

为何说要多用组合少用继承?如何决定该用组合还是继承?

Java中的继承与组合

我应该使用 ScrollView 还是 RecyclerView 在片段中滚动?

Java中的继承与组合

在摆动 GUI 中选择继承与组合 [重复]