在我目前的项目中,我有一个相当时髦的设备,可以执行各种流媒体选项,例如视频流,音频流和某些类型的数据流。
每个设备仅支持有限数量的每个流。为了论证,假设它可以支持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);
}
}
}
如您所见,FunkyDevice
和UserSession
的公共接口几乎相同,只是UserSession
中的每个方法都有一个附加参数deviceId
。在我的实际应用程序中,我有两种以上不同类型的流(并且还想执行其他操作,例如关闭流),因此接口变得非常大。
是否有更好的模式可以在不引入此代码重复的情况下实现此目的?
答案 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方法!