我在Unity3D和C#中工作,创建一个伪游戏操作系统(有点雄心勃勃)
请注意,这是一个纯粹的设计问题,您可以在不了解Unity的情况下回答.
这是我有的:
一个抽象的文件,有孩子:
> TextFile
> MediaFile
> ImageFile
此外,一个抽象的应用程序,与孩子:
> TextViewer
> MediaPlayer
> ImageViewer
显然,TextViewer应该打开TextFiles,MediaPlayer应该打开MediaFiles,而ImageViewer应该打开ImageFiles.
现在,我想了一会儿,我应该把谁打开谁的信息?
我应该让每个文件打开吗?通过在FILE中创建一个抽象Open,并覆盖子文件中的那个? – 我认为这没有意义,因为一个文件,并不真正知道如何打开自己,它是知道如何打开文件的应用程序.例如,pdf文件,如果您没有PDF阅读器(Adobe或其他),则无法打开pdf.
这意味着TextViewer应该有一个Open(TextFile文本)方法,MediaPlayer应该有一个Open(MediaFile媒体),而ImageViewer应该有一个Open(ImageFile图像)方法.
这可以通过在Application的声明中使用泛型来实现,例如:
public abstract class Application<T> where T : FILE
{
public abstract void Open(T file);
}
然后:
public class TextViewer : Application<TextFile>
{
public override void Open(TextFile file)
{
Console.WriteLine("TextViewer opening text file...");
}
}
public class MediaPlayer : Application<MediaFile>
{
public override void Open(MediaFile file)
{
Console.WriteLine("MediaPlayer opening media file...");
}
}
public class ImageViewer : Application<ImageFile>
{
public override void Open(ImageFile file)
{
Console.WriteLine("ImageViewer opening image file...");
}
}
这是UML图的样子:
看起来不错……现在有趣的部分,如何绑定/关联,每种文件类型,与正确的应用程序应该打开它?即右键单击文本文件|获取选项列表:“打开”,“重命名”,“删除”等选择“开放” – 接下来会发生什么?
我提出了一个想法,一个介于FILE和应用程序之间的中介 – 如果我们考虑一下,那么像Windows这样的真实操作系统是如何做到的? – 好吧,如果你去开始|默认程序|将文件类型或协议与程序相关联. – 你会看到一个字典类型列表,键(文件类型)和值(相关程序) – 所以我想这样做,创建一个字典,我注册,一个文件类型与应用程序.而这就是我陷入困境的地方……
首先,我应该在字典中使用什么类型的键和值? – 我想了一会儿,得出的结论应该是< Type,Application> – 但问题是,我不能单独编写Application,我必须指定泛型T参数:(
我通过创建一个inbetweener类App来攻击它,然后让我的应用程序< T>继承自:
public abstract class App { }
public abstract class Application <T> : App where T : FILE { /* stuff... */ }
好的,现在我可以让我的字典为< Type,App>
public static class Mediator
{
static private TextViewer tv;
static private MediaPlayer mp;
static private ImageViewer iv;
static private Dictionary<Type, App> dic = new Dictionary<Type, App>();
static Mediator()
{
tv = new TextViewer();
iv = new ImageViewer();
mp = new MediaPlayer();
// register what we have
dic.Add(typeof(TextFile), tv);
dic.Add(typeof(MediaFile), mp);
dic.Add(typeof(ImageFile), iv);
}
static public void Open(FILE file)
{
App app = dic[file.GetType()];
if (app == null)
{
Console.WriteLine("No application was assigned to open up " + file);
return;
}
app. // here is where my hack falls short, no Open method inside App :(
}
}
哎呀,完全没用! – 正如你所看到的,我正在尽力避免这样的事情:
if (file is TextFile)
// open with text viewer
else if (file is MediaFile)
// open with media player
else if (file is ImageFile)
// open with image viewer
else if etc
这对我来说就像是一场噩梦!
我可以通过制作我的应用程序单例来避免所有麻烦,所以现在在每个文件中:
public class TextFile : FILE
{
public override void Open()
{
TextViewer.Instance.Open(this);
}
}
等等其他文件.但我不想这样做,我不想放弃使用单身人士!如果我想让我的MediaPlayer或TextViewer拥有多个实例而不只是一个实例,该怎么办?
我现在已经在这方面苦苦挣扎了很长时间,我希望我能清楚地解决问题.我只是想知道,如何将正确的应用程序与正确的应用程序相关联(例如在Windows中) – 如何以优雅,健壮的方式实现我所追求的目标? – 我可以用这个设计模式吗? – 我上面的所有尝试,是我在想什么?我接近解决方案了吗?
非常感谢您提前提供任何帮助.
最佳答案 如果不对设计进行大量思考,不知道统一性,或者文件的真实表现方式,我将采用的方法是基于接口的方法,而不是基于通用的方法.
首先,我将定义一个定义我的文件类的接口,即IFile,并在我的每个文件中实现它.
public interface IFile
{
}
public class MediaFile : IFile
{
...
}
接下来,我将定义一个定义我的应用程序类的接口,即IApplication,并在我的每个应用程序中实现它.
public interface IApplication
{
Type GetSupportedApplicationType();
void OpenFile(IFile oFile);
}
public class MediaApplication : IApplication
{
#region IApplication Members
public Type GetSupportedApplicationType()
{
return typeof(MediaFile);
}
public void OpenFile(IFile oFile)
{
// do the work
}
#endregion
}
然后,文件和应用程序之间的链接将是一个字典,其中包含文件的类类型作为键,应用程序的类类型作为值:
<GetType(MediaFile), GetType(MediaPlayer)>
当介体传递给要执行的文件时,它可以通过使用文件类型在字典中搜索相应的应用程序类型来找到相应的应用程序.
找到合适的应用程序类型后,可以使用System.GetActivator创建它的实例.然后,由于您知道它实现了IApplication,您可以在应用程序上执行OpenFile(IFile)等方法.
唯一的技巧是创建初始字典条目.为此,我实际上会使用反射来收集实现IApplication的类列表.
完成此操作后,您可以使用System.GetActivator创建每个类的实例,然后执行一个已知方法,例如GetSupportedFileType,它返回IApplication支持的完整类型的IFile实现.
(下面的代码采用了注册应用程序的快捷方式,这比实现反射方法更容易)
public static class Mediator
{
static private Dictionary<Type, Type> dic = new Dictionary<Type, Type>();
static Mediator()
{
RegisterApp(new MediaApplication());
}
static void RegisterApp(IApplication oApp)
{
dic.Add(oApp.GetSupportedApplicationType(), oApp.GetType());
}
static public void Open(IFile file)
{
Type appType = dic[file.GetType()];
if (appType == null)
{
Console.WriteLine("No application was assigned to open up " + file);
return;
}
IApplication app = (IApplication)System.Activator.CreateInstance(appType);
app.OpenFile(file);
}
}