4

让我们假设以下类结构具有基类 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) {}
}

In '使用多态传递值对象是一种不好的做法吗?' 提出了访问者模式;

If 级联和强制转换的问题被移动(而不是消除)到抽象基类中。

有更好的解决方案来完全避免 if 吗?

我(在此示例中)无法将功能从 doX/doY 移动到类 DC_A/DC_B

非常感谢您的建议。

编辑:这个问题的背景是一个 C# / WinForms 应用程序,它有一个表单来管理一个“测试规则”,该规则由不同的子实体组成,如 TestSpec 以及一组测量类型、测试限制等(我的 DC_A、DC_B 类)所有派生自EntityBase (=BC from above) 表单向控制器发送子实体已更改的事件;简化的 PropertiesChanged(EntityBase o) 控制器调用模型类中的相应方法(上面的类 XY 中的方法 goo),它现在负责执行业务逻辑,不仅保持更改的子实体测试限制,而且例如创建一个新的测试限制修订对象,增加测试规范修订等。

但是这种特殊情况让我想到了关于多态性的更通用或“哲学”的问题;-)

4

3 回答 3

5

如果您使用的是 .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) { }
}
于 2012-12-05T11:20:05.800 回答
3

我的建议:

  1. 公开您的 doX() 和 doY() 方法,以便可以从 DC_A 和 DC_B 的实现中调用它们。
  2. 向 BC 添加一个抽象的 Do() 方法。
  3. 在 DC_A 中实现 Do() 以调用暴露的 doX() 方法。
  4. 在 DC_B 中实现 Do() 以调用公开的 doY() 方法。
  5. 在 goo() 中,只需调用 o.Do()。

您可以通过将委托传递给他们将调用的 DC_A 和 DC_B 来进一步解耦,而不是公开 doX() 和 doY()。这在很大程度上取决于使用模式。

但是,如果您可以为派生类中的 Do() 实现添加一些价值,这只会非常有用。如果 Do() 所做的只是调用 doX() 或 doY(),那么这样做并没有真正获得任何好处。

所以我会同意这里的另一张海报说只是做演员。

于 2012-12-05T09:28:11.197 回答
2

一旦我们解决了几件事,我认为不必担心太多:

  • 目前你的投射量超出了你的需要
  • 只有一个ifs 可以是真的,所以你不需要else

之后,我们有:

    // perfectly fine using polymorphism; no Ifs' no casting, OOP at its best ;-)
    o.foo();

    var dca = o as DC_A;
    if (dca != null)
    {
        doX(dca);
    }

    var dcb = o as DC_B;
    if (dcb != null)
    {
        doY(dcb);
    }

我会说看起来不错。

如果您想更进一步,您可以更改 and 的实现,doX以便doY它们在通过时立即返回null;那么你可以说

doX(o as DC_A);
doY(o as DC_B);
于 2012-12-05T09:33:59.510 回答