web-dev-qa-db-ja.com

プロトタイプデザインパターンのポイントは何ですか?

だから私は学校のデザインパターンについて学んでいます。今日、私は「プロトタイプ」の設計パターンについて話されました。

何かを見逃しているに違いありません。なぜなら、その恩恵が見えないからです。オンラインでnewを使用するよりも速いと言う人がいますが、これは意味がありません。ある時点で、新しいオブジェクトの作成方法に関係なく、メモリを割り当てる必要があります。

このパターンは、「鶏または卵」の問題と同じ円で実行されていませんか? Prototypeパターンは基本的にオブジェクトのクローンを作成するだけなので、ある時点で元のオブジェクトを作成する必要があります(つまり、クローンを作成しないでください)。これは、クローンを作成する準備ができているすべてのオブジェクトの既存のコピーが必要であることを意味しますか?

誰でもこのパターンの使用方法を説明できますか?

52
user1905391

プロトタイプパターンは、事前に構成されたオブジェクトの複製に基づいた作成パターンです。これは、デフォルトまたは特定のユースケースのボールパーク用に構成されたオブジェクトを選択し、このオブジェクトのクローンを作成して、ニーズに合わせて構成するという考え方です。

このパターンは、必要な構成が面倒な場合に、大量の定型コードを削除するのに役立ちます。 Prototypesはプリセットオブジェクトであり、状態の束を新しい開始点として保存します。

27
Mark Pauley

プロトタイプパターンには、たとえば次のような利点があります。

  • オブジェクトを初期化する(潜在的に高価な)オーバーヘッドを排除します
  • 同じタイプの複数のオブジェクトがほとんど同じデータを使用するユースケースを簡素化し、最適化できます

たとえば、プログラムが、ネットワーク経由で取得したさまざまな不変の情報から解析されたデータから作成されたオブジェクトを使用するとします。新しいオブジェクトが作成されるたびにデータを取得して再解析するのではなく、プロトタイプパターンを使用して、新しいオブジェクトが必要になったときに元のオブジェクトを単純に複製できます。

また、オブジェクトには、画像を表すデータなど、大量のメモリを消費するデータが含まれている場合があるとします。コピーオンライトスタイルの継承を使用すると、メモリを削減できます。この継承では、コードがそのデータを変更しようとするまで、複製されていない元のデータが表示されます。次に、新しいデータがマスクされ、元のデータを参照します。

41
marcus erronius

ここでの他の回答の多くは、既に構成されたオブジェクトを複製することのコスト削減について述べていますが、Prototypeパターンのもう1つの「ポイント」を拡張したいと思います。クラスがファーストクラスオブジェクトとして扱われる一部の言語では、クラス名を渡すだけで、実行時にクライアントが作成するオブジェクトのタイプを設定できます。クラスがファーストクラスオブジェクトとして扱われないC++などの言語では、Prototypeパターンを使用して同じ効果を実現できます。

たとえば、食事を作って提供することが仕事であるレストランにChefがあるとします。 Chefが低賃金で不満を抱いているとすると、彼は次のような料理を作ります。

_class Chef {
    public:
        void prepareMeal() const {
            MozzarellaSticksWithKetchup* appetizer = new MozzarellaSticksWithKetchup();
            // do something with appetizer...

            HockeyPuckHamburgerWithSoggyFries* entree = new HockeyPuckHamburgerWithSoggyFries();
            // do something with entree...

            FreezerBurnedIceCream* dessert = new FreezerBurnedIceCream();
            // do something with dessert...
        }
};
_

ここで、Chefを有名な有名シェフに変更したいとします。これは、彼がprepareMeal()new異なる料理をしなければならないことを意味します。 newChefを取得する食事のタイプをパラメーターとして指定できるように、メソッドを変更したいと思います。クラスがファーストクラスオブジェクトである他の言語では、クラス名をパラメーターとしてメソッドに渡すことができます。 C++ではこれができないため、プロトタイプパターンの恩恵を受けることができます。

_class Appetizer {
    public:
        virtual Appetizer* clone() const = 0;
        // ...
};

class Entree {
    public:
        virtual Entree* clone() const = 0;
        // ...
};

class Dessert {
    public:
        virtual Dessert* clone() const = 0;
        // ...
};

class MozzarellaSticksWithKetchup : public Appetizer {
    public:
        virtual Appetizer* clone() const override { return new MozzarellaSticksWithKetchup(*this); }
        // ...
};

class HockeyPuckHamburgerWithSoggyFries : public Entree {
    public:
        virtual Entree * clone() const override { return new HockeyPuckHamburgerWithSoggyFries(*this); }
        // ...
};

class FreezerBurnedIceCream : public Dessert {
    public:
        virtual Dessert * clone() const override { return new FreezerBurnedIceCream(*this); }
        // ...
};

// ...and so on for any other derived Appetizers, Entrees, and Desserts.

class Chef {
    public:
        void prepareMeal(Appetizer* appetizer_prototype, Entree* entree_prototype, Dessert* dessert_prototype) const {
            Appetizer* appetizer = appetizer_prototype->clone();
            // do something with appetizer...

            Entree* entree = entree_prototype->clone();
            // do something with entree...

            Dessert* dessert = dessert_prototype->clone();
            // do something with dessert...
        }
};
_

clone()メソッドは、派生型のインスタンスを作成しますが、親型へのポインターを返すことに注意してください。これは、異なる派生型を使用して作成されるオブジェクトの型を変更できることを意味し、クライアントはその違いを知りません。この設計により、プロトタイプのクライアントであるChefを構成して、実行時にさまざまな種類の料理を作成できるようになりました。

_Chef chef;

// The same underpaid chef from before:
MozzarellaSticksWithKetchup mozzarella_sticks;
HockeyPuckHamburgerWithSoggyFries hamburger;
FreezerBurnedIceCream ice_cream;
chef.prepareMeal(&mozzarella_sticks, &hamburger, &ice_cream);

// An ostentatious celebrity chef:
IranianBelugaCaviar caviar;
LobsterFrittataWithFarmFreshChives lobster;
GoldDustedChocolateCupcake cupcake;
chef.prepareMeal(&caviar, &lobster, &cupcake);
_

このように使用すると、PrototypeパターンがFactory Methodパターンと同じものを購入するのではないかと思われるかもしれません。 Factory Methodパターンには、作成される製品の階層を反映する作成者クラスの階層が必要になるためです。つまり、make()メソッドを持つMozzarellaSticksWithKetchupCreatormake()メソッドを持つHockeyPuckHamburgerWithSoggyFriesCreatorなどが必要になります。したがって、Prototypeパターンを、Factory Methodパターンによってしばしば導入されるコードの冗長性を軽減する1つの方法として単純に見ることができます。

この議論は、デザインパターン:再利用可能なオブジェクト指向ソフトウェアの要素、別名「Gang of Four」の本から引き出されています。

3
Ethan Hearne

オブジェクトを作成したいが、ネットワークまたはデータベースの呼び出しが行われる高価なオブジェクト作成手順を実行したくない場合は、プロトタイプパターンを使用します。オブジェクトのコピーを作成して、変更を加えてください。

1
user2328970

繰り返し可能なオブジェクトを含む同じデータを入力または使用する必要がある要件がある場合

そして

たとえば、[ネットワークストリームを使用してオブジェクトを構築する]などの既存のオブジェクトから構築することはできません。

オブジェクトを構築するには時間がかかります[データベースからデータを取得して大きなオブジェクトを構築する]。次に、このデザインパターンを使用します。これは、既存のオブジェクトをコピーするオリジナルのように。

0
Andy

抽象ファクトリーパターンと比較して、プロトタイプパターンを使用することで、大きなファクトリー階層は必要なく、大きな製品階層だけが必要です。

0
Michael Zheng