c# - 想要避免在传递给 Composite 的 Strategy 中向下转型

标签 c# oop design-patterns

这是我在金融行业的问题领域:

Asset
==========
Asset parent
assetID
+ compareTo(Asset anotherAsset)

Portfolio : Asset
-----------------
name
risk limit
List stocks
+ compareTo(Asset anotherAsset)
+ composite.CompareTo(Portfolio, ComparisonRules).

Stock : Asset
-------
market
amount
company
+ compareTo(Asset anotherAsset)

AnotherStock : Stock
--------------------
someOtherProperty
+ compareTo(Asset anotherAsset)

我已将复合模式应用于 *股票*s 中的 *Portfolio*s 结构。我想要一种干净的方式来自定义此组合的 compareTo 方法。也就是说,AnotherStock 将始终与另一个 AnotherStock、Stocks 与 Stocks 进行比较。这看起来像是我的策略模式。

我想做类似下面的事情(伪代码)

differences = composite.CompareTo(anotherComposite, ComparisonRules).

composite.CompareTo would be something like :

ComparisonRules.Compare(this.Stocks[currentAssetID], otherComposite[currentAssetID])

ComparisonRules.Compare(Asset a, Asset b) 会做这样丑陋的事情:

if( a is Stock and b is Stock) : convert to stock and do stock-based comparison
else if (a is AnotherStock and b is AnotherSTock): convert to AnotherStock 

有没有一种编写 ComparisonRules 的方法使我不必向下转换但仍提供自定义 ComparisonRules 对象?

最佳答案

从规则的角度来看,听起来您需要的是泛型。如果您按照以下方式定义某些内容:

public class ComparisonRule<TStock> where TStock : Stock
{
    public int Compare(TStock lValue, TStock rValue)
    {
        ...
    }
}

这将保证只有等于或低于 TStock 的类型将被接受。例如,如果我有一个 ComparisonRule<AnotherStock> , 然后只输入等于或低于 AnotherStock 的类型可以传入。但是,如果您希望能够定义一个可以比较 Stock 的规则,您可能需要重新考虑您的类型层次结构。但不是 AnotherStock .你应该考虑有一个共同的祖先,但具体的种群类型应该在不同的继承树中。

换句话说,你有这个:

              Stock
                |
    --------------------------
   |                          |
OneStock                AnotherStock 

这将允许您定义一个规则来比较任何 Stock作为ComparisonRule<Stock> , 或者只能比较 OneStock 的规则作为ComparisonRule<OneStock> .

然而,这并不能帮助您理清如何知道哪个 Stock将对象传递给更高级别的规则。为此,您需要能够定义一个不太具体的版本 ComparisonRule我们可以用一个界面来做到这一点:

public interface IComparisonRule
{
    bool CanCompare(Stock lValue, Stock rValue);
    int Compare(Stock lValue, Stock rValue);
}

public abstract class ComparisonRule<TStock> : IComparisonRule where TStock : Stock
{
    bool IComparisonRule.CanCompare(Stock lValue, Stock rValue)
    {
        return lValue is TStock && rValue is TStock;
    }

    int IComparisonRule.Compare(Stock lValue, Stock rValue)
    {
        return Compare((TStock)lValue, (TStock)rValue);
    }

    public abstract int Compare(TStock lValue, TStock rValue);
}

现在,严格来说,您的问题是问如何在不向下转型的情况下做到这一点,这(再次严格来说)是不可能的。但是,这应该使您不必在每次实现时都这样做。例如,比较两个 AnotherStock 的简单规则实例将是:

public class MyRule : ComparisonRule<AnotherStock>
{
    public override int Compare(AnotherStock lValue, AnotherStock rValue)
    {
        return lValue.someOtherProperty.CompareTo(rValue.someOtherProperty);
    }
}

在更高级别(即在 Portfolio 内),您可以简单地保留 IComparisonRule 的列表按照你的规则,那么你可以调用CanCompare并传入两个 Stock实例以查看它是否是有效比较,然后将它们传递给 Compare以便进行比较。

关于c# - 想要避免在传递给 Composite 的 Strategy 中向下转型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7135557/

相关文章:

c# - 在策略模式中,处理共享行为的最佳方式是什么?

C# Xamarin Forms MessagingCenter 不更新项目通过

c# - 集合属性应该是只读的——漏洞?

需要 JavaScript OOP 辅助

c++ - 带有 2 个列表的面向对象

testing - 如何组织和测试这段代码?

java - 哪种设计模式适合可数对象?

c# - 在两个 Activity 之间来回传递数据

c# - 使用空数组反序列化 XML 返回一个包含单个对象的数组

c# - 如何在 C# 中将任何类型的数字作为参数接受到函数中?