如何干净地不同的行为基于多态处理 [英] How to cleanly deal with different behavior based on polymorphism

查看:149
本文介绍了如何干净地不同的行为基于多态处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个接口的IFoo 与实现类 VideoFoo AudioFoo TextFoo 。进一步假设,我不能修改任何的code。假设我会那么喜欢写了不同的行为根据的IFoo 的运行时类型的函数,如

Suppose I have an interface IFoo with implementation classes VideoFoo, AudioFoo, and TextFoo. Suppose further that I cannot modify any of that code. Suppose that I would then like to write a function that acts differently based on the runtime type of IFoo, such as

Public Class Bar
    Public Shared Sub Fix(ByVal Foo as IFoo)
        If TypeOf Foo Is VideoFoo Then DoBar1()
        If TypeOf Foo Is AudioFoo Then DoBar2()
        If TypeOf Foo Is TextFoo Then DoBar3()

    End Sub
End Class

我想重构这个使用重载的方法:

I would like to refactor this to use overloaded methods:

Sub DoBar(ByVal foo as VideoFoo)
Sub DoBar(ByVal foo as AudioFoo)
Sub DoBar(ByVal foo as TextFoo)

但我看到做这样的事情,唯一的办法是写

But the only way I see to do something like that would be to write

Sub DoBar(ByVal foo as IFoo)

然后,我必须做我的如果TypeOf运算...是一次。我该如何重构这个利用的IFoo 的实现的多态性,而无需手动检查类型?

Then I have to do my "If TypeOf ... Is" again. How can I refactor this to take advantage of the polymorphism of the implementations of IFoo without manually checking the types?

(在VB.NET,虽然我的问题适用于C#太)

(in VB.NET, though my question applies to C# too)

推荐答案

那么,一个选择是简单地重载修正()的方法,让你有一个过载每种类型的实施的IFoo 。但我怀疑你想直接接受界面,而不是它的实现类型。

Well, one option is to simply overload the Fix() method so that you have one overload for each type implementing IFoo. But I suspect you want to accept the interface directly, rather than it's implementing types.

什么,你实际上是在寻找的是多分派通常情况下,C#/ VB使用参数(S)的类型进行重载在编译时,呼叫基础上该方法被称为实例的运行时类型的动态调度。你想要的是来的在运行时根据的运行的类型参数进行重载的 - 一个功能,无论是VB.NET或C#直接支持。

What you're actually looking for is multiple dispatch. Normally, C#/VB use the types of the argument(s) to perform overload resolution at compile time, and dynamic dispatch of the call based on the runtime type of the instance on which the method is called. What you want is to perform overload resolution at runtime based on the runtime types of the arguments - a feature that neither VB.NET or C# directly support.

在过去,我通常解决这类问题使用由的System.Type 索引代表字典:

In the past, I've generally solved this kind of problem using a dictionary of delegates indexed by System.Type:

private readonly Dictionary<Type,Action<IFoo>> _dispatchDictionary;

static Bar()
{
    _dispatchDictionary.Add( typeof(TextFoo),  DoBarTextFoo );
    _dispatchDictionary.Add( typeof(AudioFoo), DoBarAudioFoo );
    _dispatchDictionary.Add( typeof(VideoFoo), DoBarVideoFoo );        
}

public void Fix( IFoo foo )
{
   Action<IFoo> barAction;
   if( _dispatchDictionary.TryGetValue( foo.GetType(), out barAction ) )
   {
      barAction( foo );
   }
   throw new NotSupportedException("No Bar exists for type" + foo.GetType());
}

private void DoBarTextFoo( IFoo foo ) { TextFoo textFoo = (TextFoo)foo; ... }
private void DoBarAudioFoo( IFoo foo ) { AudioFoo textFoo = (AudioFoo)foo; ... }
private void DoBarVideoFoo( IFoo foo ) { VideoFoo textFoo = (VideoFoo)foo; ... }

不过,由于C#4,我们现在可以使用动态的关键字在C#中做基本上做同样的事情(VB.NET不具备此功能作为然而):

However, as of C# 4, we can now use the dynamic keyword in C# do essentially do the same thing (VB.NET does not have this feature as of yet):

public void Fix( IFoo foo )
{
    dynamic dynFoo = foo;
    dynamic thisBar = this;

    thisBar.DoBar( dynFoo ); // performs runtime resolution, may throw
}

private void Dobar( TextFoo foo ) { ... /* no casts needed here */ }
private void Dobar( AudioFoo foo ) { ... }
private void Dobar( VideoFoo foo ) { ... }

注意使用动态关键字这种方式有一个价格 - 它需要调用点在运行时处理。它本质上旋转了一个版本的C#编译器在运行时,处理由编译器捕获的元数据,执行各类运行时分析,并吐出C#code。幸运的是,在DLR可以在他们第一次使用后,有效。典型的缓存催缴网站。

Note that using the dynamic keyword this way has a price - it requires that the call site be processed at runtime. It essentially spins up a version of the C# compiler at runtime, processes the metadata captured by the compiler, performs runtime analysis of the types, and spits out C# code. Fortunately, the the DLR can typicall cache such call sites effectively after their first use.

作为一般规则,我觉得这两个图案是混乱,矫枉过正的大多数情况下。如果亚型的数量很少,他们都提前知道,一个简单的的if / else 块可bemuch简单和清晰。

As a general rule, I find both of these pattern to be confusing, and overkill for most situations. If the number of subtypes is small and they are all known ahead of time, a simple if/else block can bemuch simpler and clearer.

这篇关于如何干净地不同的行为基于多态处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆