我目前正在使用一些旧的C#代码,它基本上使用派生类型,其唯一目的是将Type用作“属性”,例如:
public abstract class Fruit
{
public int Property { get; set; }
}
public class Apple : Fruit {}
public class Pear : Fruit {}
然后:
public void Foo(Fruit item)
{
if(item is Apple)
{
// do something
return;
}
if(item is Pear)
{
// do something
return;
}
throw new ArgumentOutOfRangeException("item");
}
我会在BaseClass上包含一个enum属性来指定'type':
public class Fruit
{
public int Property { get; set; }
public FruitType Type { get; set; }
}
public enum FruitType
{
Apple,
Pear
}
然后用它:
public void Foo(Fruit item)
{
switch(item.Type)
{
case FruitType.Apple:
// do something
break;
case FruitType.Pear:
// do something
break;
default:
throw new ArgumentOutOfRangeException();
}
}
我觉得前一种模式是对继承的滥用,但是在重写这段代码之前我应该考虑一下它有什么好处吗?
答案 0 :(得分:12)
处理这种情况的标准“OO”方法是将DoSomething作为Fruit上的抽象方法。然后调用者只需调用DoSomething,知道实现将做正确的事情。
这种方法的缺点是它负责将用户可能想要的所有可能“某些东西”解决到抽象类的作者身上。
使用“访客模式”可以减轻这种负面影响。访问者模式是使第三方能够根据值的运行时类型有效切换行为的标准方法。你可以考虑研究它。
您的第二种方法 - 使用标签区分类型 - 非常常见且非常有效。罗斯林广泛使用这种技术。 OO纯粹主义者认为它有点臭,但幸运的是我不是OO纯粹主义者。
我喜欢的第二种技术的变体是:
public enum FruitKind { Apple, Orange }
public abstract class Fruit
{
private Fruit(FruitKind kind)
{
this.Kind = kind;
}
public FruitKind Kind { get; protected set; }
private class Apple : Fruit
{
public Apple() : base(FruitKind.Apple) {}
}
public static Fruit MakeApple() { return new Apple(); }
// similarly for orange
}
现在,水果用户可以通过标签确定类型的仅方式,因为Apple和Orange无法访问。你知道没有第三方可以制作他们自己的Fruit,因为唯一的Fruit构造函数是私有的。