C# 防止几乎相同接口的代码重复
在我目前的项目中,我有一个相当时髦的设备,可以执行各种流媒体选项,例如,视频流、音频流和某些类型的数据流 每个设备仅支持有限数量的每个流。为了便于论证,假设它可以支持2个视频流和1个音频流 我设计的有点像下面。(大多数应用程序逻辑被忽略。)C# 防止几乎相同接口的代码重复,c#,design-patterns,C#,Design Patterns,在我目前的项目中,我有一个相当时髦的设备,可以执行各种流媒体选项,例如,视频流、音频流和某些类型的数据流 每个设备仅支持有限数量的每个流。为了便于论证,假设它可以支持2个视频流和1个音频流 我设计的有点像下面。(大多数应用程序逻辑被忽略。) 公共类FunkyDevice { int开放视频流; int openAudioStreams; 公共视频流openVideoStream(int id) { 如果(openVideoStreams
公共类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(…);
//做一些定制的东西
}
}
总之:
- 泛型和继承一起提供了代码重用
- 多态性使您有机会重用基类实现并重写它们以满足更具体的需求
- 否:openVideoStream
- OK:OpenVideoStream
instance.OpenAudioStream(新用户streamingsettings{DevideId=3,StreamId=38})
。