資産運用会社について考えないことから始めます。大まかに定義された用語(「マネージャー」など)でアーキテクチャを考えると、敷居の下で多くの詳細を精神的に一掃する傾向があり、その結果、解決策を見つけるのが難しくなります。
特定のニーズに焦点を当てます。これは、基になるオリジンストレージを抽象化し、サポートされているタイプセットの拡張性を可能にするリソースロードメカニズムの作成に関係しているようです。たとえば、既にロードされたリソースのキャッシュに関する質問には本当に何もありません-これは問題ありません。単一の責任原則に従って、おそらくアセットキャッシュを別のエンティティとして構築し、2つのインターフェイスを別の場所に集約する必要があるためです、 適切に。
特定の懸念に対処するには、アセット自体の読み込みを行わず、特定の種類のアセットの読み込みに合わせたインターフェイスにその責任を委任するようにローダーを設計する必要があります。例えば:
interface ITypeLoader {
object Load (Stream assetStream);
}
このインターフェイスを実装する新しいクラスを作成できます。新しいクラスはそれぞれ、ストリームから特定のタイプのデータをロードするように調整されます。ストリームを使用することにより、タイプローダーは一般的なストレージに依存しないインターフェイスに対して記述でき、ディスクまたはデータベースからロードするためにハードコーディングする必要はありません。これにより、ネットワークストリームからアセットをロードできるようになります(ゲームがコンソールで実行され、編集ツールがネットワークに接続されたPCで実行されている場合、アセットのホットリロードを実装するのに非常に役立ちます)。
メインのアセットローダーは、これらのタイプ固有のローダーを登録および追跡できる必要があります。
class AssetLoader {
public void RegisterType (string key, ITypeLoader loader) {
loaders[key] = loader;
}
Dictionary<string, ITypeLoader> loaders = new Dictionary<string, ITypeLoader>();
}
ここで使用する「キー」は好きなものにできます。文字列である必要はありませんが、簡単に開始できます。キーは、ユーザーが特定の資産を識別する方法を考慮し、適切なローダーを検索するために使用されます。実装がファイルシステムまたはデータベースを使用している可能性があるという事実を隠したいので、ファイルシステムパスまたはそのようなものでアセットを参照するユーザーを作成することはできません。
ユーザーは最小限の情報でアセットを参照する必要があります。場合によっては、ファイル名だけで十分な場合もありますが、すべてが非常に明確になるように、タイプと名前のペアを使用することが望ましい場合が多いことがわかりました。したがって、ユーザーは、アニメーションXMLファイルの名前付きインスタンスをとして参照する場合があります"AnimationXml","PlayerWalkCycle"
。
ここでAnimationXml
はAnimationXmlLoader
、を実装するキーを登録しますIAssetLoader
。明らかにPlayerWalkCycle
、特定の資産を識別します。タイプ名とリソース名を指定すると、アセットローダーは、そのアセットの未加工バイトについて永続ストレージを照会できます。ここでは最大限の汎用性を求めているため、ローダーを作成するときにローダーにストレージアクセスの手段を渡すことでこれを実装でき、ストレージメディアを後でストリームを提供できるものに置き換えることができます。
interface IAssetStreamProvider {
Stream GetStream (string type, string name);
}
class AssetLoader {
public AssetLoader (IAssetStreamProvider streamProvider) {
provider = streamProvider;
}
object LoadAsset (string type, string name) {
var loader = loaders[type];
var stream = provider.GetStream(type, name);
return loader.Load(stream);
}
public void RegisterType (string type, ITypeLoader loader) {
loaders[type] = loader;
}
IAssetStreamProvider provider;
Dictionary<string, ITypeLoader> loaders = new Dictionary<string, ITypeLoader>();
}
非常に単純なストリームプロバイダーは、指定されたアセットのルートディレクトリで名前の付いたサブディレクトリを探し、指定されtype
たファイルの未加工バイトをname
ストリームにロードして、それを返します。
つまり、ここにあるのは次のようなシステムです。
- ある種のバックエンドストレージ(ディスク、データベース、ネットワークストリームなど)から生のバイトを読み取る方法を知っているクラスがあります。
- 生のバイトストリームを特定の種類のリソースに変換して返す方法を知っているクラスがあります。
- 実際の「アセットローダー」には上記のコレクションがあり、ストリームプロバイダーの出力をタイプ固有のローダーにパイプして具体的なアセットを生成する方法を知っています。ストリームプロバイダーとタイプ固有のローダーを構成する方法を公開することにより、実際のアセットローダーコードを変更することなく、クライアント(またはユーザー)によって拡張できるシステムができます。
いくつかの注意事項と最終ノート:
上記のコードは基本的にC#ですが、最小限の労力でほぼすべての言語に翻訳する必要があります。これを容易にするために、エラーチェックや適切な使用IDisposable
など、他の言語に直接適用されない可能性のある他のイディオムなど、多くのことを省略しました。それらは読者の宿題として残されています。
同様に、object
上記の具体的なアセットを返しますが、必要に応じてジェネリックやテンプレートなどを使用して、より具体的なオブジェクトタイプを生成できます(作業するのは良いことです)。
上記のように、ここではキャッシュをまったく扱いません。ただし、同じ種類の一般性と構成可能性を備えたキャッシングを簡単に追加できます。試してみてください!
これを行うにはたくさんの方法がたくさんあり、確かに一つの方法もコンセンサスもありません。だからあなたはそれを見つけることができなかったのです。この答えを非常に長いコードの壁に変えることなく、特定のポイントを理解するのに十分なコードを提供しようとしました。すでに非常に長いです。明確な質問がある場合は、気軽にコメントしたり、チャットで私を見つけてください。