让我们假设以下类结构具有基类 BC 和 2 个派生类 DC_A 和 DC_B; 此外,还有一个 XY 类,其方法 goo() 的参数类型为 BC 和其他方法
// base class
public class BC
{
public virtual void foo();
}
// derived class A
public class DC_A : BC
{
public override void foo() {}
}
// derived class B
public class DC_B : BC
{
public override void foo() {}
}
public class XY
{
public void goo(BC o)
{
// perfectly fine using polymorphism; no Ifs' no casting, OOP at its best ;-)
o.foo();
// but what to do here?
if ( (o as DC_A) != null )
{
doX(o as DC_A);
}
else if ((o as DC_B) != null)
{
doY(o as DC_B);
}
}
private void doX(DC_A o) {}
private void doY(DC_B o) {}
}
在 'Is passing around value objects using polymorphism a bad practice? ' Visitor模式被提出;
If 级联和强制转换的问题被移动(而不是消除)到抽象基类中。
是否有更好的解决方案来完全避免 if's?
我(在本例中)无法将功能从 doX/doY 移至类 DC_A/DC_B
非常感谢您的建议。
编辑: 这个问题的背景是一个 C#/WinForms 应用程序,它有一个表单来管理一个“测试规则”,该规则由不同的子实体组成,比如 TestSpec 和一组测量类型、测试限制等(我的 DC_A、DC_B 类)所有派生来自 EntityBase(=BC 从上面) 表单向 Controller 发送一个子实体已更改的事件; 简化的 PropertiesChanged(EntityBase o) Controller 调用模型类中的相应方法(上面 XY 类中的方法 goo),该方法现在负责执行业务逻辑,该业务逻辑不仅保留更改的子实体测试限制,而且例如创建新的测试限制修订对象,增加测试规范修订等。 也许以这种方式 具有像 PropertiesChanged(EntityBase o) 这样的方法的通用方法应该更改为来自表单的更具体的事件以及 Controller 和模型类中的特定事件处理程序以处理“TestLimitChanged”等。
但是这个特例让我想到了关于多态性的更普遍或更“哲学”的问题 ;-)
最佳答案
如果您使用的是 .NET 4,则可能会出现重载和动态类型,这可能是您的替代方案。
class Program
{
static void Main(string[] args)
{
DC_A dca = new DC_A();
DC_B dcb = new DC_B();
XY xy = new XY();
xy.goo(dca);
xy.goo(dcb);
}
}
// base class
public abstract class BC
{
public abstract void foo();
}
// derived class A
public class DC_A : BC
{
public override void foo() { }
}
// derived class B
public class DC_B : BC
{
public override void foo() { }
}
public class XY
{
//public void goo<T>(T o) where T : BC
//{
// //dynamic dyn = Convert.ChangeType(o, o.GetType());
// //dynamic dyn = o;
// //gooi(dyn);
// gooi((dynamic)o);
//}
// http://smellegantcode.wordpress.com/2008/11/04/dynamic-typing-in-c-4-and-duck-generics/
public void goo<T>(T o) where T : BC
{
gooi((dynamic)o);
}
private void gooi(DC_A o)
{
o.foo();
doX(o);
}
private void gooi(DC_B o)
{
o.foo();
doY(o);
}
private void gooi(BC o)
{
o.foo();
}
private void doX(DC_A o) { }
private void doY(DC_B o) { }
}
关于c# - 如何使用多态避免 'If cascade' 和类型转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13719780/