防止几乎相同的接口的代码重复

时间:2013-08-08 09:54:20

标签: c# design-patterns

在我目前的项目中,我有一个相当时髦的设备,可以执行各种流媒体选项,例如视频流,音频流和某些类型的数据流。

每个设备仅支持有限数量的每个流。为了论证,假设它可以支持2个视频流和1个音频流。

我的设计有点像下面。 (大多数应用程序逻辑都被遗漏了。)

public class FunkyDevice
{
    int openVideoStreams;
    int openAudioStreams;

    public VideoStream openVideoStream(int id)
    {
        if (openVideoStreams < 2)
        {
            openVideoStreams++;
            return new VideoStream(...);
        }
    }
    public AudioStream openAudioStream(int id)
    {
        if (openAudioStreams < 1) 
        {
            openAudioStreams++;
            return new AudioStream(...);            
        }
    }
}

但是,现在我需要支持多个设备。我在用户会话中对这些进行分组。每个用户会话也限制每个流的数量,但当然这些数字与设备限制不同(否则问题会太容易)。例如,我可以有3个视频流(可以是1个,2个或3个不同的设备),还有1个音频流。

我最好的处理方法如下:

public class UserSession
{
    int openVideoStreams;
    int openAudioStreams;

    public VideoStream openVideoStream(int deviceId, int id)
    {
        if (openVideoStreams < 3)
        {
            openVideoStreams++;
            return getDevice(deviceId).openVideoStream(id);
        }
    }
    public AudioStream openAudioStream(int deviceId, int id)
    {
        if (openAudioStreams < 1) 
        {
            openAudioStreams++;
            return getDevice(deviceId).openAudioStream(id);     
        }
    }
}

如您所见,FunkyDeviceUserSession的公共接口几乎相同,只是UserSession中的每个方法都有一个附加参数deviceId。在我的实际应用程序中,我有两种以上不同类型的流(并且还想执行其他操作,例如关闭流),因此接口变得非常大。

是否有更好的模式可以在不引入此代码重复的情况下实现此目的?

2 个答案:

答案 0 :(得分:4)

您可以根据标识符类创建一个通用的接口:

public interface IStreamManager<TIdentifier>{

 VideoStream openVideoStream(TIdentifier id);
 AudioStream openAudioStream(TIdentifier id);

}

,第一个你有的地方:

public class FunkyDeviceStreamIdentifier {
   public int id;
}

对于第二个你有:

public class UserDeviceStreamIdentifier {
   public int deviceId;
   public int id;
}

(您可能希望改为使用struct,和/或引入工厂方法或隐式转换,以便更容易处理)

答案 1 :(得分:1)

我一直在考虑解决方案,也许有一种可以让生活更轻松的解决方案。

您可以拥有StreamingSettings课程:

public class StreamingSettings
{
    public int StreamId { get; set; }
}

您还可以设计继承StreamingSettings

的用户会话流设置类
public class UserSessionStreamingSettings : StreamingSettings
{
    public int DeviceId { get; set; }
}

现在,您可以按如下方式使用泛型:

    // Check that the generic constraint enforces that 
    // only StreamingSettings or a derived class will be valid generic arguments!
public class FunkyDevice<TStreamingSettings> where TStreamingSettings : StreamingSettings
{
    public virtual VideoStream openVideoStream(TStreamingSettings settings)
    {
        if (openVideoStreams < 2)
        {
            openVideoStreams++;
            return new VideoStream(...);
        }
    }
    public virtual AudioStream openAudioStream(TStreamingSettings settings)
    {
        if (openAudioStreams < 1) 
        {
            openAudioStreams++;
            return new AudioStream(...);            
        }
    }
}

public class UserSession : FunkyDevice<UserStreamingSettings>
{
    public override VideoStream openVideoStream(UserStreamingSettings settings)
    {
        // Do some custom stuff
        // Call here the base class' implementation
        base.openVideoStream(...);
        // Do some custom stuff
    }
    public override AudioStream openAudioStream(UserStreamingSettings settings)
    {
        // Do some custom stuff
        // Call here the base class' implementation
        base.openAudioStream(...);
        // Do some custom stuff
    }
}

总结:

  • 泛型和继承一起为您提供代码重用。
  • 多态性使您有机会重用基类实现并覆盖它们以满足更具体的要求。

注意:.NET约定建议使用pascal-casing方法!

  • :openVideoStream
  • 确定:OpenVideoStream