我在Unity3D和C#中工作以创建一个伪游戏操作系统(有点雄心勃勃)
请注意,这是一个纯粹的设计问题,您可以在不了解Unity的情况下回答。
这就是我所拥有的:
带有孩子的抽象FILE
:
TextFile
MediaFile
ImageFile
另外,一个抽象的Application
,带有孩子:
TextViewer
MediaPlayer
ImageViewer
显然,TextViewer
应该打开TextFile
,MediaPlayer
应该打开MediaFile
,ImageViewer
应该打开ImageFile
。
现在,我想了一会儿,我应该把 who-opens-whom 信息放在哪里?
我应该让每个文件打开吗?通过在Open
中创建一个抽象FILE
,并覆盖子文件中的那个? - 我认为这没有意义,因为一个文件,并不真正知道如何打开自己,它是知道如何打开文件的应用程序。例如,pdf文件,如果您没有PDF阅读器(Adobe或其他东西),则无法打开pdf。
这意味着TextViewer
应该有Open(TextFile text)
方法,MediaPlayer
应该有Open(MediaFile media)
,而ImageViewer
应该有Open(ImageFile image)
方法。
这可以通过在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
和Application
之间的中介的想法 - 如果我们考虑一下,像Windows这样的真实操作系统是如何做到的? - 好吧,如果你去开始|默认程序|将文件类型或协议与程序相关联。 - 你会看到一个字典类型列表,键(文件类型)和值(相关程序) - 所以我想这样做,创建一个字典,我注册,一个文件类型与应用程序。而这就是我被困在......
首先,我应该在字典中使用什么类型的键和值? - 我想了一会儿,得出的结论应该是<Type, Application
&gt; - 但问题是,我不能单独编写Application
,我必须指定通用T
参数:(
我通过创建一个inbetweener类App
来攻击它,然后让我的Application<T>
继承自:{/ p>
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中) - 如何以优雅,健壮的方式实现我所追求的目标? - 我可以用这个设计模式吗? - 我上面的所有尝试,是我在想什么?我接近解决方案吗?
非常感谢您提前提供任何帮助。
答案 0 :(得分:1)
也许这对你有用,而不是在应用程序类中声明一个抽象方法 并创建泛型,您可以创建一个接口并实现其开放方法,如下所示:
public interface IFile<T>
{
void Open(T path);
}
public abstract class Application
{
//public abstract void Open();
}
public class TextViewer : Application, IFile<TextFile>
{
public void Open(TextFile path)
{
//open textfile....
}
}
public class MediaPlayer : Application, IFile<MediaFile>
{
public void Open(MediaFile path)
{
//open media file...
}
}
public class ImageViewer : Application, IFile<ImageFile>
{
public void Open(ImageFile path)
{
//open imagefile....
}
}
答案 1 :(得分:1)
如果没有对设计进行大量思考,不知道统一性,或者文件的真实表现方式,我将采用的方法是基于接口的方法,而不是基于通用的方法。
首先,我将定义一个定义我的文件类的接口,即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
,返回IFile
的完整类型IApplication
支持的实现。
(下面的代码采用了注册应用程序的快捷方式,这比实现反射方法更容易)
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);
}
}