操作系统设计问题:与其相应程序关联的文件类型

时间:2013-10-26 23:28:25

标签: c# inheritance polymorphism unity3d

我在Unity3D和C#中工作以创建一个伪游戏操作系统(有点雄心勃勃)

UA Crosslink

请注意,这是一个纯粹的设计问题,您可以在不了解Unity的情况下回答。

这就是我所拥有的:

带有孩子的抽象FILE

  1. TextFile
  2. MediaFile
  3. ImageFile
  4. 另外,一个抽象的Application,带有孩子:

    1. TextViewer
    2. MediaPlayer
    3. ImageViewer
    4. 显然,TextViewer应该打开TextFileMediaPlayer应该打开MediaFileImageViewer应该打开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图的样子:

      enter image description here

      看起来不错......现在有趣的部分,如何绑定/关联,每个文件类型,与正确的应用程序应该打开它?即右键单击文本文件|获取选项列表:“打开”,“重命名”,“删除”等选择“打开” - 接下来会发生什么?

      我提出了FILEApplication之间的中介的想法 - 如果我们考虑一下,像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);
         }
      }
      

      等等其他文件。但我不想这样做,我不想放弃使用单身人士!如果我希望我的MediaPlayerTextViewer拥有多个实例而不只是一个实例,该怎么办?

      我现在已经在这方面挣扎了很长时间,我希望我能清楚地解决问题。我只是想知道,如何将正确的应用程序与正确的应用程序相关联(例如在Windows中) - 如何以优雅,健壮的方式实现我所追求的目标? - 我可以用这个设计模式吗? - 我上面的所有尝试,是我在想什么?我接近解决方案吗?

      非常感谢您提前提供任何帮助。

2 个答案:

答案 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);
    }
}