4

私は Unity3D と C# でゲーム内の疑似オペレーティング システムを作成しています (ちょっと野心的です)。

UAクロスリンク

これは純粋な設計上の質問であり、Unity について何も知らなくても答えられることに注意してください。

ここに私が持っているものがあります:

子を持つ抽象FILE:

  1. TextFile
  2. MediaFile
  3. ImageFile

また、子を持つ抽象Application:

  1. TextViewer
  2. MediaPlayer
  3. ImageViewer

明らかに、sをTextViewer開く必要があり、s を開く必要があり、 s を開く必要があります。TextFileMediaPlayerMediaFileImageViewerImageFile

さて、しばらく考えてみたのですが、誰が誰を開封したかの情報はどこに入れればよいのでしょうか。各ファイルを開く必要がありますか? で要約を作成OpenFILE、子ファイルでそれを上書きすることによって?- それは意味がないと思います。なぜなら、ファイルは自分自身を開く方法を本当に知らないからです。ファイルを開く方法を知っているのはアプリケーションです。たとえば、pdf ファイルの場合、pdf リーダー (Adobe など) がなければ、pdf を開くことはできません。

これは、メソッドがTextViewer必要であり、メソッドが必要であり、メソッドが必要であることを意味します。Open(TextFile text)MediaPlayerOpen(MediaFile media)ImageViewerOpen(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 のような実際の OS はどのようにそれを行うのでしょうか? -まあ、あなたが行くならスタート| デフォルト プログラム | ファイルの種類またはプロトコルをプログラムに関連付けます。- キー (ファイル タイプ) と値 (関連するプログラム) の辞書タイプ リストが表示されます。そして、ここで私は立ち往生しています...

まず、辞書で検索する必要があるキーと値のタイプは何ですか? - しばらく考えて、次のようなものにするべきだという結論に達しました<Type, Application>ApplicationT

私はそれをハックし、in betweener クラスAppを作成してから継承させApplication<T>ました:

public abstract class App { }

public abstract class Application <T> : App where T : FILE { /* stuff... */ }

OK、これで私の辞書は<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に 1 つだけでなく複数のインスタンスを持たせたい場合はどうすればよいですか?

私はこれに長い間苦労してきました。問題が明確になったことを願っています。ファイルタイプを適切なアプリケーションに関連付ける方法が正しい方法 (Windows など) でどのように機能するのかを知りたいだけです。- これに使用できるデザイン パターンはありますか? - 上記のすべての試みは、正しく考えていましたか? 私は解決策に近づいていますか?

事前に助けてくれてありがとう。

4

2 に答える 2

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などの既知のメソッドを実行できます。GetSupportedFileTypeIFileIApplication

(以下のコードは、リフレクション アプローチを実装するよりも簡単な、アプリの登録への近道です)

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);
    }
}
于 2013-10-26T23:56:49.550 に答える