Best way to switch behavior based on type
Possible Duplicate:
C# - Is there a better alternative than this to ‘switch on type’?
考虑经典:
1 2 3 | class Widget { } class RedWidget : Widget { } class BlueWidget : Widget { } |
在我的用户界面中,大多数情况下,我可以对所有的
可能的方法:
枚举指示器-由构造函数设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | enum WidgetVariety { Red, Blue } class Widget { public WidgetVariety Variety { get; protected set; } } class RedWidget : Widget { public RedWidget() { Variety = Red; } } // Likewise for BlueWidget... switch (mywidget.Variety) { case WidgetVariety.Red: // Red specific GUI stuff case WidgetVariety.Blue: // Blue specific GUI stuff } |
使用
1 2 3 4 5 6 7 |
我之所以这么做是因为1)大部分代码都是这样写的,但是更糟糕。2)90%的代码是相同的-基本上,网格视图中的一列需要根据类型进行不同的处理。
你会推荐哪一个?(或者谁有更好的解决方案?)
编辑我知道我可能会被推荐给访问者模式,但对于这种情况下的稀疏、微小的差异来说,这似乎很复杂。
编辑2所以有一个特别的区别,我在整理时遇到了困难,那就是这个列在这两种类型之间是不同的。在一种情况下,它检索一个
我想在这种情况下,很明显我可以定义:
1 2 3 4 5 | public object virtual GetColumn4Data(); public override GetColumn4Data() { return m_boolval; } public override GetColumn4Data() { return m_mystring; } |
由于使用了
今天在办公室呆得太久了,好像…
还有另一种可能性。使用虚拟调度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Widget { public virtual void GuiStuff() { } } class RedWidget : Widget { public override void GuiStuff() { //... red-specific GUI stuff base.GuiStuff(); } } class BlueWidget : Widget { public override void GuiStuff() { //... blue-specific GUI stuff base.GuiStuff(); } } |
子类型多态性是最好的解决方案,避免这种检查是创建OO的主要原因之一。
另见Martin Fowler的用多态性替换条件:
Seen: You have a conditional that chooses different behavior depending on the type of an object.
Refactor: Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.
对于编辑2下的问题,您可以使用一个通用类使类型在子类中有所不同,尽管根据您的设计,它可能适用,也可能不适用。这可能会导致其他艰难的设计决策。
粗略实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | internal abstract class BaseClass { protected object mValue; // could also be defined as a T in BaseClass<T> public object GetColumn4Data { get { return mValue; } } } // this is a group of classes with varying type internal abstract class BaseClass<T> : BaseClass { public T GetTypedColumn4Data { get { return (T)mValue; } set { mValue = value; } } } // these are not really necessary if you don't plan to extend them further // in that case, you would mark BaseClass<T> sealed instead of abstract internal sealed class BoolSubClass : BaseClass<bool> { // no override necessary so far } internal sealed class StringSubClass : BaseClass<string> { // no override necessary so far } |
但是,请注意,您不能真正获得在某些属性或方法上具有不同返回类型的单个引用类型。