子类型多态性,而不向派生类添加依赖项

本文关键字:派生 添加 依赖 类型 多态性 | 更新日期: 2023-09-27 18:02:32

Setup

假设我有一个树结构,其节点都派生自抽象类FruitNode

public abstract class FruitNode : Tree<FruitNode>
{
    public double NodeId { get; private set; }
    public FruitType Type { get; private set; }
    protected FruitNode(double nodeId, FruitType fruitType)
    {
        NodeId = nodeId;
        Type = fruitType;
    }
    public abstract double GetMagicalFruitValue();
}
所有派生类

都包含一个方法,用于设置派生类上的一些附加字段。这些私人字段是计算神奇水果价值所必需的。

例如,Banana派生类可能如下所示。

public class Banana : FruitNode
{
    private List<double> _bananaSecretValues;
    public Banana(double id) : base(id, FruitType.Banana) {}
    public void SetAdditionalBananaData2(List<double> computedBananaValues)
    {
        _bananaSecretValues = computedBananaValues;
    }
    public override double GetMagicalFruitValue()
    {
        return Math.Exp(_bananaSecretValues.Sum());
    }
}

以及一个Orange派生类。

public class Orange : FruitNode
{
    private List<double> _orangeSecretValueList1;
    private List<double> _orangeSecretValueList2; 
    public Orange(double id) : base(id, FruitType.Orange) {}
    public void SetAdditionalOrangeData(List<double> 
        computedList1Values, List<double> computedList2Values)
    {
        _orangeSecretValueList1 = computedList1Values;
        _orangeSecretValueList2 = computedList2Values;
    }
    public override double GetMagicalFruitValue()
    {
        return Math.Cos(_orangeSecretValueList1.Zip(_orangeSecretValueList2,
            (one, two) => one - two).Average());
    }
}

问题

FruitNode树首先设置为"骨架",没有设置每个节点上的附加信息。

在程序的稍后阶段,我需要在FruitNode树中的每个节点上设置其他数据。水果节点的所有其他数据都来自类型 Economy 的同一对象。

当前的解决方案是遍历树结构中的所有节点,并实现对节点FruitType是什么的switch。然后将节点强制转换为其相应的派生类。

    public void SetAdditionalFruitTreeData(IEnumerable<FruitNode> nodesInFruitTree, Economy economy)
    {
        foreach (var node in nodesInFruitTree)
        {
            switch (node.Type)
            {
                case FruitType.Banana:
                {
                    List<double> computedBananaValues = new List<double>();
                    // do some manipulations with the economy to add values to
                    //    the computed banana values
                    // cast the node to the derived type Banana, and call
                    //    the SetAdditionalBananaData class 
                    break;
                }
                case FruitType.Orange:
                {
                    List<double> computedBananaValues = new List<double>();
                    // do some manipulations with the economy to add values to
                    //    the computed banana values
                    // cast the node to the derived type Orange, and call
                    //    the SetAdditionalOrangeData
                    break;
                }
                // continued for other fruit types
            }
        }
    }

但这很丑陋。对我来说,这看起来像是亚型多态性的一个很好的用例。我可以添加一个

    public abstract void SetAdditionalData(Economy economy);

到抽象基FruitType类,然后将逻辑委托给每个派生类本身,以继续从Economy进行所需的任何计算。

但是Economy是来自FruitType树类的外部依赖关系,我不允许FruitType类依赖于Economy类,如果我继续使用抽象方法方法,它们显然会成为。

我的问题是,有没有另一种方法可以模拟多态子类型,而无需在子类中添加对所讨论方法参数的依赖关系?

<小时 />

对于可能人为的例子,我深表歉意(我对 OOP 不是很强烈(,如果有任何不清楚的地方,请告诉我,我会相应地澄清。

子类型多态性,而不向派生类添加依赖项

实现一个名为 IFruitNode 的接口,所有水果节点都实现该接口。它的方法之一是 SetAdditionalFruitTreeData .然后,您的示例Tree<FruitNode>将被Tree<IFruitNode>,因此您现有的SetAdditionalFruitTreeData将只循环所有节点并调用IFruitNode.SetAdditionalFruitTreeData()方法。然后,FruitTree类将不依赖于IFruitNode的实现者。