0

工場のゲームを作っています。工場には、物が入った箱が移動しています。時々、アイテムを含むクレートを含むデポがあり、ワーカーは利用可能なクレートで特定のタイプのアイテムを探す必要があります (たとえば、ワーカーは、「食品を含むデポにクレートはありますか? 」 もしそうなら、彼はそれを拾いに行き、どこかに移動します.

"Crate" クラスと "Furniture" クラス (Depot が継承する) の両方を Generics で定義して、それらに含まれるオブジェクトのタイプを指定することは非常に便利に思えました。以下は、私のクレート クラスと家具クラス、そして私が苦労しているデポ クラスのスニペットです。

public class Crate<I> : Item 
    where I : Item
{
}

public abstract class Furniture<I>
    where I : Item
{
}

public class Depot : Furniture<Crate<???>>
{
    //...
}

ジェネリックは、次のような検索メソッドを記述できるため、ここで役立ちます。

public I FindItem<I,F>
 where I:Item
 where F:Furniture<I>
{
    //pseudocode

    //foreach (furniture f in the factory);
    //if (f is F) foreach (I i in f)
    //if (i.IsAvailable) return i;

    //return null;
}

さて、私の問題は、他のほとんどの家具とは異なり、デポは何でも入ったクレートを取ることができるということです(例えば、食料のクレートと原材料のクレートの両方)。しかし、Crate(Item) だけを指定することはできません。検索アルゴリズムが台無しになるからです。Crates of Food を検索すると、Crates of Items しか含まれていないため、null が返されます。

Crate 用のジェネリックを保持し、StorageFurniture 用に破棄し、検索アルゴリズムを少し長くする必要があります (つまり、正しいタイプのアイテムを含む家具だけでなく、すべての家具を検索します)、またはこの問題を回避する方法はありますか?

4

2 に答える 2

1

Crate-able オブジェクトのルート クラスまたはインターフェイスを作成することを検討してください。

public class Crate<I> : Item 
    where I : Item
{
    private int capacity;
    private List<I> contents;
    //... and so on
}

public interface ICrateable{
// define common features such as name, ID, description etc here
}

public class Shirt: ICrateable{
// implement interface
}


public class DepotSlot : StorageFurniture<Crate<ICrateable>>
{
    // now you can add any Crate<XYZ> here
}

Crate-s を処理している場合、それらで行う共通の操作を用意することだけが理にかなっています - それらを開く、閉じる、ラベルを貼る、廃棄する、トラックに積み込む、荷降ろしするなどです。これらすべての共通事項機能は、ルート (抽象?) クラスまたはインターフェイスで抽象化できます。

クレートで事前定義された操作がない場合は、それらを作成ojectしてジェネリックを放棄することもできます

于 2013-02-11T19:14:38.647 に答える
0

ゲームがショップ内で「自己完結型」であり、ベース タイプを変更してすべてを再コンパイルしても過度の負担にならない場合は、ベースの「GameObject」タイプに多数の仮想メソッドを用意することをお勧めします。 、および特定のオブジェクトに対してどのメソッドが何かを行うかを (「フラグ」列挙を介して) 示すフィールドがあります。ゲーム オブジェクトのリストがあり、そのリスト内のすべてのオブジェクトに対して、そのアクションが関連するアクションを実行したい場合 (たとえば、爆弾が爆発し、爆発範囲内のすべての損傷可能なアイテムを「損傷」したい場合)、無条件に実行する方が高速です。仮想メソッドを呼び出すことは、インターフェイスを実装しているかどうかをオブジェクトごとにテストし、実装している場合はオブジェクトでそのインターフェイスを呼び出すよりも、すべてのオブジェクトに共通です (何もしないオブジェクトも含む)。

オブジェクトに関連する呼び出しのタイプを示すフィールドを使用すると、システムが仮想メソッド呼び出しの前に何らかの作業を実行することを回避できるため、場合によってはパフォーマンスが向上することがあります。たとえば、フィールドをテストして、オブジェクトがTakeBombDamage呼び出しに対して何もしないことが明らかになった場合、オブジェクトが受けるダメージの量を計算する時間を無駄にする必要はありません。

仮想メソッドを基本クラスに追加して、すべてではなく一部のオブジェクトに存在する機能をサポートするアプローチを採用すると、実行時の型キャストを実行する必要性を最小限に抑えることができます。これにより、ジェネリックの必要性が減少します。「キッチン シンク ベース クラス」アプローチは、ベース クラスへの変更が面倒な状況では適していませんが、パフォーマンスが重要な状況、特に適切なデフォルトが存在する動作 (たとえば、「FlashingStrobe」ゲーム オブジェクトの場合) では役立ちます。近くのオブジェクトの呼び出しNoticeFlashingStrobe、点滅するストロボを気にしないオブジェクトは、そのようなメソッドでは賢明に何もしないかもしれません)。

于 2013-02-11T19:25:46.877 に答える