70

なので、学校でデザインパターンについて学んでいます。今日は「プロトタイプ」のデザインパターンを教えてもらいました。

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

このパターンは「ニワトリが先か卵が先か」の問題と同列ではないでしょうか? Prototype パターンは基本的にオブジェクトのクローンを作成するだけなので、ある時点で元のオブジェクト自体を作成する必要があります (つまり、クローンを作成しないでください)。これは、複製したいすべてのオブジェクトの既存のコピーを複製する準備ができている必要があることを意味しますか?

このパターンの用途を説明できる人はいますか?

4

7 に答える 7

51

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

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

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

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

于 2012-12-15T00:14:20.373 に答える
34

Prototype パターンは、事前構成されたオブジェクトの複製に基づく作成パターンです。アイデアは、デフォルトまたは特定のユースケースの球場のいずれかで構成されているオブジェクトを選択し、このオブジェクトを複製して正確なニーズに合わせて構成することです。

このパターンは、必要な構成が面倒な場合に、ボイラープレート コードの束を削除するのに役立ちます。Prototypes は、一連の状態を新しい開始点として保存するプリセット オブジェクトと考えています。

于 2012-12-14T23:34:44.600 に答える
11

ここでの他の回答の多くは、構成済みのオブジェクトを複製することによるコスト削減について述べていますが、Prototype パターンの他の「ポイント」について詳しく説明したいと思います。クラスがファーストクラスのオブジェクトとして扱われる一部の言語では、クラス名を渡すだけで、実行時にクライアントによって作成されるオブジェクトのタイプを構成できます。クラスがファーストクラスのオブジェクトとして扱われない 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ここで、 を派手な有名シェフに変更したいとしましょう。これは、彼/彼女が でnew別の料理を食べなければならないことを意味しprepareMeal()ます。newで取得する食事の種類をChefパラメータとして指定できるようにメソッドを修正したいと思います。クラスがファースト クラス オブジェクトである他の言語では、クラス名をパラメーターとしてメソッドに渡すだけです。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 パターンでは、作成される製品の階層を反映するクリエーター クラスの階層が必要になるためです。つまり、MozzarellaSticksWithKetchupCreatorwith a make()method 、HockeyPuckHamburgerWithSoggyFriesCreatorwith a method などが必要make()になります。したがって、Prototype パターンは、Factory Method パターンによってしばしば導入されるコードの冗長性を軽減する 1 つの方法と見なすことができます。

この議論は、 Design Patterns: Elements of Reusable Object-Oriented Software、別名「Gang of Four」の本から引き出されています。

于 2018-06-21T15:34:16.470 に答える