我正在使用Unity3D和C#创建一个媒体播放器应用程序。
(我的问题与Unity无关,这是一个纯粹的设计问题)
以下是我目前的情况:
IApp
界面,包含实施者:
TextViewer
ImageViewer
MediaPlayer
IFile
界面,包含实施者:
TextFile
ImageFile
MediaFile
- 有孩子:
VideoFile
AudioFile
这是界面:
public interface IApp
{
void Open(IFile file);
Type SupportedType { get; }
}
每个应用都有一个可以打开的特定支持文件类型。
关于我MediaPlayer
的一句话是,它打开/播放音频和视频文件。但是我打开视频的方式与我打开音频的方式不同,所以每种方式都有一个独特的逻辑。
现在这里是代码 - 非常简单(但尚未完全实现):
public class MediaPlayer : IApp
{
public Type SupportedType { get { return typeof(MediaFile); } }
public void Open(IFile file)
{
if (file is MediaFile)
Console.WriteLine("MediaPlayer opening media file...");
}
List<MediaFile> Medias = new List<MediaFile>();
public MediaFile Current { private set; get; }
public PlaybackControls Controls { private set; get; }
public PlaybackSettings Settings { private set; get; }
public MediaPlayer()
{
Controls = new PlaybackControls(this);
Settings = new PlaybackSettings(this);
}
public class PlaybackControls
{
private MediaPlayer player;
private int index;
public PlaybackControls(MediaPlayer player)
{
this.player = player;
}
public void Seek(float pos) { }
public void Next()
{
index = (index + 1) % player.Medias.Count;
player.Current = player.Medias[index];
}
public void Previous()
{
index--;
if (index < 0)
index = player.Medias.Count - 1;
player.Current = player.Medias[index];
}
private void PlayVideo(VideoFile video)
{
// video logic
}
private void PlayAudio(AudioFile audio)
{
// audio logic
}
public void Play(MediaFile media)
{
IsPlaying = true;
if (media is AudioFile)
PlayAudio(media as AudioFile);
else if (media is VideoFile)
PlayVideo(media as VideoFile);
}
public void Play()
{
Play(player.Current);
}
public void Pause()
{
IsPlaying = false;
}
public void Stop()
{
IsPlaying = false;
Seek(0);
}
public bool IsPlaying { get; private set; }
}
public class PlaybackSettings
{
// Volume, shuffling, looping, etc
}
}
我不太喜欢的是Play(Media)
方法。在内部,我正在检查媒体类型,并且根据媒体是视频还是音频,我正在调用正确的方法。我不喜欢那样,我觉得这不对。如果我有其他类型的媒体,如图片怎么办?如果我想在ImageFile
下移动MediaFile
该怎么办?
然后我必须添加另一个else-if
语句,它根本不是多态的。
我可以做的是让媒体文件选择要调用的方法,例如:
public abstract class MediaFile : IFile
{
//...
public abstract void Open(MediaPlayer from);
//...
}
public class AudioFile : MediaFile
{
public override void Open(MediaPlayer from)
{
from.PlayAudio(this);
}
}
public class VideoFile : MediaFile
{
public override void Open(MediaPlayer from)
{
from.PlayVideo(this);
}
}
现在在MediaPlayer
:
public void Open(MediaFile media)
{
media.Open(this); // polymorphically open it
}
没有别的 - 如果,好的!但这引入了我不喜欢的其他不便之处:
VideoFile
&amp; MediaPlayer
和AudioFile
&amp; MediaPlayer
现在更加紧密耦合。MediaPlayer
必须知道Audio/VideoFile
,反之亦然)Audio/VideoFile
能够自己打开自己是不合理的(尽管他们并没有真正这样做,他们只是告诉MediaPlayer
打开它们。MediaPlayer
应该知道怎么做,他不需要任何人告诉他如何做他的工作。)或者
MediaPlayer.Open(Media) -> AudioFile.Open(AudioFile) -> MediaPlayer.OpenAudio(AudioFile)
或
MediaPlayer.Open(Media) -> VideoFile.Open(VideoFile) -> MediaPlayer.OpenVideo(VideoFile)
我们以多态的名义绕着自己盘旋,我们可以直接找到正确的方法。
我认为上述两种方法都不是最好的,但如果我选择一种,我会选择第一种。
你怎么看?有没有更好的办法? - 一种漂亮,优雅,强大的多态方式,一举一动地射击所有鸟类?我该怎么办呢?也许我可以在这里使用一种设计模式?如果我的判断错了,请纠正我。
非常感谢您提前提供任何帮助。
答案 0 :(得分:1)
你有几个选择。
1)使用委托字典并根据委托运行的文件类型进行选择:
public class PlaybackControls
{
private MediaPlayer player;
private int index;
Dictionary<string, Action<MediaFile>> _fileActionMethods;
public PlaybackControls(MediaPlayer player)
{
this.player = player;
_fileActionMethods = new Dictionary<string, Action<MediaFile>>();
_fileActionMethods.Add(typeof(VideoFile).Name, x => PlayVideoFile(x));
_fileActionMethods.Add(typeof(AudioFile).Name, x => PlayAudioFile(x));
}
public void Seek(float pos) { }
public void Next()
{
index = (index + 1) % player.Medias.Count;
player.Current = player.Medias[index];
}
public void Previous()
{
index--;
if (index < 0)
index = player.Medias.Count - 1;
player.Current = player.Medias[index];
}
public void Play(MediaFile media)
{
IsPlaying = true;
_fileActionMethods[media.GetType().Name](media);
}
public void Play()
{
Play(player.Current);
}
public void Pause()
{
IsPlaying = false;
}
public void Stop()
{
IsPlaying = false;
Seek(0);
}
public bool IsPlaying { get; private set; }
private void PlayVideoFile(MediaFile file) { }
private void PlayAudioFile(MediaFile file) { }
}
2)第二个选项基于类似的动态选择概念,但使用另一个抽象层,使您能够使用单独的类处理每个文件。由于缺乏想象力,我将其命名为IFileActionHandler.
它现在只有一种方法,但如果需要,可以添加更多方法。下面的示例显示了如何根据文件类型动态选择正确的实现。我在构造函数中创建了这些实现的字典。根据实现的内存占用量有多大,您可能需要考虑另一种方法 - 在静态文件(XML,config,txt等)中定义键值对,并使用{{1}之一创建正确的实例重载。
System.Acticator.CreateInstance