2

在我无法修改的类中实现多态行为的最佳方法是什么?我目前有一些代码,例如:

if(obj is ClassA) {
    // ...
} else if(obj is ClassB) {
    // ...
} else if ...

显而易见的答案是在基类中添加一个虚拟方法,但不幸的是代码在不同的程序集中,我无法修改它。有没有比上面丑陋而缓慢的代码更好的方法来处理这个问题?

4

5 回答 5

9

嗯...似乎更适合Adapter

public interface ITheInterfaceYouNeed
{
    void DoWhatYouWant();
}

public class MyA : ITheInterfaceYouNeed
{
    protected ClassA _actualA;

    public MyA( ClassA actualA )
    {
        _actualA = actualA;
    }

    public void DoWhatYouWant()
    {
        _actualA.DoWhatADoes();
    }
}

public class MyB : ITheInterfaceYouNeed
{
    protected ClassB _actualB;

    public MyB( ClassB actualB )
    {
        _actualB = actualB;
    }

    public void DoWhatYouWant()
    {
        _actualB.DoWhatBDoes();
    }
}

看起来像很多代码,但它会使客户端代码更接近你想要的。另外,它会让您有机会思考您实际使用的界面。

于 2009-03-25T20:59:06.010 回答
5

查看访客模式。这使您可以在不更改类的情况下向类添加虚拟方法。如果您使用的基类没有 Visit 方法,则需要使用带有动态转换的扩展方法。这是一些示例代码:

public class Main
{
    public static void Example()
    {
        Base a = new GirlChild();
        var v = new Visitor();
        a.Visit(v);
    }
}

static class Ext
{
    public static void Visit(this object b, Visitor v)
    {
        ((dynamic)v).Visit((dynamic)b);
    }
}

public class Visitor
{
    public void Visit(Base b)
    {
        throw new NotImplementedException();
    }

    public void Visit(BoyChild b)
    {
        Console.WriteLine("It's a boy!");
    }

    public void Visit(GirlChild g)
    {
        Console.WriteLine("It's a girl!");            
    }
}
//Below this line are the classes you don't have to change.
public class Base
{
}

public class BoyChild : Base
{
}

public class GirlChild : Base
{
}
于 2009-03-25T20:56:02.147 回答
0

我想说这里的标准方法是将要“继承”的类包装为受保护的实例变量,然后在容器中模拟包装类的所有非私有成员(方法/属性/事件/等)班级。然后,您可以将此类及其相应成员标记为虚拟,以便您可以使用标准的多态特性。

这是我的意思的一个例子。ClosedClass是程序集中包含的类,您无权访问其代码。

public virtual class WrapperClass : IClosedClassInterface1, IClosedClassInterface2
{
    protected ClosedClass object;

    public ClosedClass()
    {
        object = new ClosedClass();
    }

    public void Method1()
    {
        object.Method1();
    }

    public void Method2()
    {
        object.Method2();
    }
}

如果您引用的任何程序集设计得很好,那么您可能想要访问的所有类型/成员都将被适当标记(抽象、虚拟、密封),但不幸的是事实并非如此(有时您甚至可以体验到这一点基类库的问题)。在我看来,包装类是要走的路。它确实有它的好处(即使您想要派生的类可继承的),即删除/更改您不希望类的用户访问的方法的修饰符。BCL 中的ReadOnlyCollection<T>是一个很好的例子。

于 2009-03-25T21:04:11.207 回答
0

看一下装饰器模式。诺多林实际上在没有给出模式名称的情况下解释了它。

装饰器是不继承而扩展行为的方式。我在诺多林的代码中唯一要改变的是构造函数应该接收你正在装饰的对象的一个​​实例。

于 2009-03-25T22:25:48.717 回答
-1

扩展方法提供了一种向现有类添加附加方法签名的简单方法。这需要3.5框架。

创建一个静态实用程序类并添加如下内容:

public static void DoSomething(this ClassA obj, int param1, string param2)
{
    //do something
}

在页面上添加对实用程序类的引用,该方法将作为 ClassA 的成员出现。您可以通过这种方式重载现有方法或创建新方法。

于 2009-03-25T21:32:31.060 回答