【问题标题】:Best way to switch behavior based on type [duplicate]根据类型切换行为的最佳方法[重复]
【发布时间】:2012-04-24 07:04:11
【问题描述】:

可能重复:
C# - Is there a better alternative than this to ‘switch on type’?

考虑经典:

class Widget { }
class RedWidget : Widget { }
class BlueWidget : Widget { }

在大多数情况下,在我的 UI 中,我可以一视同仁地对待所有 Widgets。但是,有一些细微的差异,我需要通过ifswitch

可能的方法:

枚举指标 - 由构造函数设置

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
}

使用is

Widget w = ...;
if (w is RedWidget) {
    (RedWidget)w ...
}
else if (w is BlueWidget) {
    (BlueWidget)w ...
}

我采用这种方式的原因是 1) 大部分代码已经以这种方式编写,但更难看。 2) 90% 的代码是相同的——基本上 GridView 中的一列需要根据类型进行不同的处理。

你会推荐哪个? (或者任何人有更好的解决方案?)


编辑我知道我可能会被推荐给访问者模式,但在这种情况下,对于稀疏的、微小的差异来说,这似乎很复杂。

编辑 2 因此,我很难理清的一个特别区别是这两种类型之间的不同。在一种情况下,它检索bool 值,并将其分配给网格单元。在另一种情况下,它获取一个字符串值。

我想在这种情况下,很明显我可以定义:

public object virtual GetColumn4Data();

public override GetColumn4Data() { return m_boolval; }

public override GetColumn4Data() { return m_mystring; }

由于使用了object,最初我觉得这不对。但是,我在单元格中分配给的属性的类型,所以当然这是有道理的!

今天似乎在办公室太久了……

【问题讨论】:

标签: c# polymorphism


【解决方案1】:

对于编辑#2 下的问题,您可以使用泛型类来使类型在子类之间有所不同,但根据您的设计,它可能适合您,也可能不适合您。这可能会导致其他艰难的设计决策。

粗略的例子:

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
}

但是请注意,您无法真正获得在某些属性或方法上具有不同返回类型的单一引用类型。 BaseClass 引用最多只能返回一个通用类型(如 object)。

【讨论】:

  • 不幸的是,这在这里行不通。这种特殊的类型差异只是几个小但重要的差异之一。如果这是唯一的区别,我会同意这种方法。
【解决方案2】:

Subtype polymorphism 是最好的解决方案,避免这种检查是创建 OO 的主要原因之一。

Widget 可能有一个方法DoSomething()(可能是抽象的)然后RedWidgetBlueWidget 将覆盖它。

另见 Martin Fowler 的Replace Conditional with Polymorphism

Seen:您有一个根据对象类型选择不同行为的条件。

重构:将条件的每个分支移动到子类中的覆盖方法。将原始方法抽象化。

【讨论】:

  • 我不同意 [这种] 多态性是“为什么要创建 OO”的想法;它更像是某些“OO 语言”的效果。但是,其他位 +1。 (有更多种类的多态而不是无聊——而且很危险!——例如,在 C#/Java 中发现的单调度子类型。)
  • @pst 我明白你的意思,有趣的话题
【解决方案3】:

还有另一种可能。使用虚拟调度:

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();
    }
} 

【讨论】:

  • 当然.... 见我的编辑 2 :-)
猜你喜欢
  • 2014-10-05
  • 2021-12-31
  • 2014-02-17
  • 1970-01-01
  • 1970-01-01
  • 2018-10-15
  • 2016-11-29
  • 2017-11-04
  • 1970-01-01
相关资源
最近更新 更多