目前我正在使用一些旧的 C# 代码,这些代码基本上使用派生类型的唯一目的是将类型用作“属性”,例如:
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 上包含一个枚举属性来指定“类型”:
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();
}
}
我觉得前一种模式是对继承的滥用,但是在重写这段代码之前我应该考虑它有什么优点吗?
最佳答案
处理这种情况的标准“面向对象”方法是使 DoSomething 成为 Fruit 上的抽象方法。然后调用者只需调用 DoSomething,知道实现将做正确的事情。
这种方法的缺点是它将计算出用户可能想要的所有可能“东西”的责任推给了抽象类的作者。
可以通过使用“访问者模式”来减轻这种不利影响。访问者模式是一种标准方式,使第三方能够根据值的运行时类型有效地切换行为。您可以考虑对其进行研究。
您的第二种方法——使用标签区分类型——很常见并且非常有效。 Roslyn 广泛使用了这种技术。 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
}
现在,Fruit 用户可以唯一确定类型的方法是通过标记,因为无法访问 Apple 和 Orange。您知道没有第三方会制作自己的 Fruit,因为唯一的 Fruit 构造函数是私有(private)的。
关于c# - 将 Type 用作 'Property' 是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14449699/