Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 防止几乎相同接口的代码重复_C#_Design Patterns - Fatal编程技术网

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

C# 防止几乎相同接口的代码重复,c#,design-patterns,C#,Design Patterns,在我目前的项目中,我有一个相当时髦的设备,可以执行各种流媒体选项,例如,视频流、音频流和某些类型的数据流 每个设备仅支持有限数量的每个流。为了便于论证,假设它可以支持2个视频流和1个音频流 我设计的有点像下面。(大多数应用程序逻辑被忽略。) 公共类FunkyDevice { int开放视频流; int openAudioStreams; 公共视频流openVideoStream(int id) { 如果(openVideoStreams

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

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

我设计的有点像下面。(大多数应用程序逻辑被忽略。)

公共类FunkyDevice
{
int开放视频流;
int openAudioStreams;
公共视频流openVideoStream(int id)
{
如果(openVideoStreams<2)
{
openVideoStreams++;
返回新的视频流(…);
}
}
公共音频流openAudioStream(int id)
{
如果(openAudioStreams<1)
{
openAudioStreams++;
返回新的音频流(…);
}
}
}
但是,现在我需要支持多个设备。我在用户会话中将它们分组。每个用户会话也会限制每个流的数量,但当然这些数量与设备限制不同(否则问题就太容易了)。例如,我可以有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);     
        }
    }
}
    // 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(...);            
        }
    }
}
公共类用户会话
{
int开放视频流;
int openAudioStreams;
公共视频流openVideoStream(int设备id,int id)
{
如果(openVideoStreams<3)
{
openVideoStreams++;
返回getDevice(deviceId).openVideoStream(id);
}
}
公共音频流openAudioStream(int设备id,int id)
{
如果(openAudioStreams<1)
{
openAudioStreams++;
返回getDevice(deviceId).openAudioStream(id);
}
}
}
如您所见,
FunkyDevice
UserSession
的公共接口几乎相同,只是
UserSession
中的每个方法都有一个附加参数
deviceId
。在我的实际应用程序中,我有两种以上不同类型的流(并且还希望执行其他操作,例如关闭流),因此接口变得相当大


是否有更好的模式可以在不引入代码重复的情况下简化此过程?

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

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;
}

(您可能想让它们成为结构,和/或引入工厂方法或隐式转换,使它们更容易处理)

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

您可以拥有一个
StreamingSettings
类:

public class StreamingSettings
{
    public int StreamId { get; set; }
}
您还可以设计一个用户会话流媒体设置类,该类继承
流媒体设置

public class UserSessionStreamingSettings : StreamingSettings
{
    public int DeviceId { get; set; }
}
现在,您可以按如下方式使用泛型:

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);     
        }
    }
}
    // 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(...);            
        }
    }
}
//检查泛型约束是否强制
//只有StreamingSettings或派生类才是有效的泛型参数!
公共类FunkyDevice,其中TStreamingSettings:StreamingSettings
{
公共虚拟视频流openVideoStream(TStreamingSettings)
{
如果(openVideoStreams<2)
{
openVideoStreams++;
返回新的视频流(…);
}
}
公共虚拟音频流openAudioStream(TStreamingSettings)
{
如果(openAudioStreams<1)
{
openAudioStreams++;
返回新的音频流(…);
}
}
}
以及:

公共类用户会话:FunkyDevice
{
公共覆盖视频流openVideoStream(用户流设置)
{
//做一些定制的东西
//这里调用基类的实现
base.openVideoStream(…);
//做一些定制的东西
}
公共覆盖音频流openAudioStream(用户流设置)
{
//做一些定制的东西
//这里调用基类的实现
base.openAudioStream(…);
//做一些定制的东西
}
}
总之:

  • 泛型和继承一起提供了代码重用
  • 多态性使您有机会重用基类实现并重写它们以满足更具体的需求
注意:.NET约定建议方法使用pascal大小写

  • 否:openVideoStream
  • OK:OpenVideoStream

我想您不能使用抽象类,因为您已经从其他类进行了扩展?为什么不在两者中都使用附加参数?第一个类可以忽略it@x4rf41他们可能会,但我不喜欢这个概念,因为设备和会话在“现实世界”中并不是真正的兄弟。它们也没有真正共享一个接口,因为会话工作在更高的“数量级”(或者无论如何应该这样称呼)上很好!我喜欢这种方法!谢谢,这看起来也很有用:)是的,我是一个Java爱好者,我总是需要一些后处理来更新我的字段和公共方法名;-)@没问题。Java,Java,Java GRR!!:D检查C#是否支持类型初始值设定项,使某些事情变得更容易。例如,
instance.OpenAudioStream(新用户streamingsettings{DevideId=3,StreamId=38})