Reputation: 13177
In my current project, I have a rather funky device, that can perform all kinds of streaming options, for instance, video streaming, audio streaming, and certain kinds of data streaming.
Each device only supports a limited number of each of these streams. For the sake of argument, assume it can support 2 video streams and 1 audio stream.
I designed it somewhat like below. (Most application logic is left out.)
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(...);
}
}
}
However, now I need to support more than 1 device. I group these in a user session. Every user session also limits the number of each stream, but of course these numbers are not the same as the device limitations (otherwise the problem would be too easy). For instance, I can have 3 video streams (to either 1, 2, or 3 different devices) and still 1 audio stream.
My best attempt to deal with this is as follows:
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);
}
}
}
As you can see, the public interfaces of FunkyDevice
and UserSession
are almost identical, except that every method in UserSession
has an additional parameter deviceId
. In my real application, I have much more than 2 different types of streams (and also want to perform other operations, such as closing the streams), so the interfaces become quite large.
Is there a nicer pattern to facilitate this without introducing this code duplication?
Upvotes: 3
Views: 112
Reputation: 64931
I've been thinking about a solution and maybe there's one that could make life easier.
You can have an StreamingSettings
class:
public class StreamingSettings
{
public int StreamId { get; set; }
}
You can also design a user session streaming settings class which inherits StreamingSettings
:
public class UserSessionStreamingSettings : StreamingSettings
{
public int DeviceId { get; set; }
}
Now, you can use generics as follows:
// 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(...);
}
}
}
And:
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
}
}
In summary:
Some note: .NET conventions recommends pascal-casing for methods!
Upvotes: 1
Reputation: 239646
You can make an interface that's generic in terms of the identifier class:
public interface IStreamManager<TIdentifier>{
VideoStream openVideoStream(TIdentifier id);
AudioStream openAudioStream(TIdentifier id);
}
, where for the first you'd have:
public class FunkyDeviceStreamIdentifier {
public int id;
}
And for the second you'd have:
public class UserDeviceStreamIdentifier {
public int deviceId;
public int id;
}
(You may want to make them struct
s instead, and/or introduce factory methods or implicit conversions that make them easier to deal with)
Upvotes: 4