Here is my problem domain in the financial industry :
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)
I have applied the composite pattern to structure *Stock*s within *Portfolio*s. I want to have a clean way of customizing the compareTo method of this composite. That is, AnotherStock will always be compared to another AnotherStock, Stocks to Stocks. This looks like the strategy pattern to me.
I would like to do something like the following (psuedocode)
differences = composite.CompareTo(anotherComposite, ComparisonRules). composite.CompareTo would be something like : ComparisonRules.Compare(this.Stocks[currentAssetID], otherComposite[currentAssetID])
ComparisonRules.Compare(Asset a, Asset b) would do something ugly like this :
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
Is there a way to write ComparisonRules in such a way that I don’t have to downcast yet still provide a custom ComparisonRules object?
From a rule perspective, it sounds like what you need are generics. If you define something along these lines:
That will guarantee that only types at or below
TStockwill be accepted. For example, if I had aComparisonRule<AnotherStock>, then only types at or belowAnotherStockcould be passed in. However, you may want to rethink your type hierarchy if you want to be able to define a rule that can compareStockbut notAnotherStock. You should consider having a common ancestor, but the concrete stock types should be in different inheritance trees.In other words, you have this:
This would allow you to define a rule that could compare any
StockasComparisonRule<Stock>, or a rule that can only compareOneStockasComparisonRule<OneStock>.This, however, doesn’t help you sort out how to know which
Stockobjects to pass to which rules at a higher level. For that, you’ll need to be able to define a less-specific version ofComparisonRuleWe can do that with an interface:Now, strictly speaking, your question asked how to do this without downcasting, which (again, strictly speaking) isn’t possible. This, however, should save you from having to do that with every implementation. For example, a simple rule to compare two
AnotherStockinstances would be:At the higher level (i.e. within
Portfolio), you can simply hold on to a list ofIComparisonRuleas your rules, then you can callCanCompareand pass in twoStockinstances to see if it’s a valid comparison, then pass them intoComparein order to perform the comparison.