LoginSignup
1
2

More than 1 year has passed since last update.

デザインパターン_Prototype

Posted at

参照

6.Prototype パターン
Prototype を C++ で
デザインパターン「Prototype」
wiki-Prototypeパターン
Prototypeパターンのメリットや使いどころは?

クラス図

Prototypeパターン クラス図
wiki-Prototypeパターンより引用

Prototypeパターンとは

Prototypeパターンとは,生成に関するデザインパターンである.
目的は,一度生成したオブジェクトを複製して新しいオブジェクトを生成するという内容となっている

使用例

「直線を描く」機能しか持たない図形エディターを想像してみましょう。この図形エディターで星型を書きたいときには、直線を組み合わせることで、星の形を作成していくことになります。では、星型がいくつも欲しいときはどうすればよいでしょう?直線を組み合わせて星型を描くという作業を何度も繰り返す必要が出てきます。こんなとき、最初に作成した星型(直線の集まり)を「プロトタイプ」として登録しておき、これをコピーすることで星型が作成できれば、作業がとても楽になります。

6.Prototypeパターン より引用

つまり,値が少しだけ違うクラスを大量に作る場合などの場合に使用すると
クラスを減らせて可読性が上がる,という風になる

メリット

1.種類が多すぎて、クラスにまとめられない場合
2.クラスからのインスタンス生成が難しい場合
3.フレームワークと生成するインスタンスを分けたい場合

Prototypeパターンのメリットや使いどころは?より引用

種類が多すぎて、クラスにまとめられない場合

Prototypeパターンを使わなければ、フィールドの値が少し違うだけのクラスがたくさん作られてしまう。
または、1個のクラスにまとめて、コンストラクタの引数にフィールドの値を渡すかだ。
どちらにおいてもフィールドの値が少し違うだけのインスタンスを新たに生成する場合は、
コンストラクタを使ってnewする必要がある。
これは、コンストラクタ内の処理が軽ければ、それほど問題がないように思える。
しかし、処理が非常に重く時間がかかる場合に、必要な種類分すべてnewしてインスタンスを生成するのは面倒である。
そういう時に、プロトタイプとなるインスタンスを登録しておけば、コピーしていろんなインスタンスを作れるし、
クラス数も減らせるので便利だなと思った。

Prototypeパターンのメリットや使いどころは?より引用

クラスからのインスタンス生成が難しい場合

例えば、ゲームに複数個の同じ爆弾を登場させる時や、パワポの図形をコピーするときなどに使われているみたい。
ユーザのマウス操作を通して作成された複雑な図形やグラフィックをプログラム上で
コンストラクタを使って再現するのは面倒そうだし、重たい処理をしなければいけないのが想像できる。
そこでPrototypeパターンを使うと、2回目以降のインスタンス生成が非常に低コストで行える。

Prototypeパターンのメリットや使いどころは?より引用

フレームワークと生成するインスタンスを分けたい場合

Prototypeパターンではコピー対象のクラスは必ず、
Prototypeになるためのインタフェースを実装しているので、
Client側ではインスタンスをコピーする際に具体的なクラス名について知っておく必要がない。
つまり、フレームワーク側が具体的なクラス名に束縛されないということである。

Prototypeパターンのメリットや使いどころは?より引用

処理

  • Client: Manager
  • Prototype: Prototype
  • ConcretePrototype: MessageBox, UnderLinePen

デザインパターン「Prototype」を参考に実装しました.

Main

Main.cpp
#include <iostream>
#include "Manager.h"
#include "MessageBox.h"
#include "UnderLinePen.h"

using namespace std;

int main()
{
    Manager* manager = new Manager();
    {
        manager->Register<MessageBox>("Box", '@');
        manager->Register<MessageBox>("line", '*');
        manager->Register<UnderLinePen>("under", '_');
    }

    {
        Prototype* p1 = manager->Create("Box");
        p1->Use("this is p1");
        delete p1;

        Prototype* p2 = manager->Create("line");
        p2->Use("this is p2");
        delete p2;

        Prototype* p3 = manager->Create("under");
        p3->Use("this is p3");
        delete p3;
    }

    delete manager;

    return 0;
}

Client: Manager

  • ConcretePrototypeの登録
  • 設定されたクラスの複製する関数を呼び出している
C++ Manager.h
#include <unordered_map>
#include <string.h>
#include "Prototype.h"

class Manager {
private:
    std::unordered_map<string, Prototype*> Prototypes;

public:
    Manager() {}

    ~Manager() {
        if (!Prototypes.empty()) {
            Prototypes.clear();
        }
    }

    template <class T>
    void Register(string name, char emoji) { Prototypes[name] = new T(emoji); }

    Prototype* Create(string Name) { return Prototypes[Name]->Clone(); }

};

Prototype: Prototype

  • 複製に必要な要素を仮想関数で定義している
Prototype.h
#include <string>
#include <iostream>
using namespace std;

class Prototype
{
protected:
    string Message;
    char Emoji;

public:
    Prototype(char emoji):
        Emoji(emoji),
        Message()
    {};

    virtual ~Prototype() {};

    virtual Prototype* Clone() const = 0;

    virtual void Use(string)const = 0;

};

ConcretePrototype: MessageBox, UnderLinePen

  • 文字を囲む処理
  • Managerで複製関数が呼ばれた際にCloneが呼び出される.
MessageBox.h
#include<string.h>
#include <unordered_map>
#include "Prototype.h"

using namespace std;

class MessageBox :public Prototype
{
public:
    MessageBox(char emoji) :
        Prototype(emoji)
    {}

    void Use(const string message)const override {
        int length = message.length();
        Line(length);

        cout << Emoji << " " << message << " " << Emoji << endl;

        Line(length);
    }

    Prototype* Clone()const override { return new MessageBox(*this); }

private:
    void Line(const int length)const {
        int space = 4;
        for (int i = 0; i < length + space; i++)
        {
            cout << Emoji;
        }
        cout << endl;
    }

};
  • 文字列に下線を表示
  • Managerで複製関数が呼ばれた際にCloneが呼び出される.
UnderLinePen
#include<string.h>
#include <unordered_map>
#include "Prototype.h"

using namespace std;

class UnderLinePen :public Prototype
{
public:
    UnderLinePen(char emoji) :
        Prototype(emoji)
    {}

    void Use(const string message)const override {
        int length = message.length();
        cout << message << endl;
        Line(length);
    }

    Prototype* Clone()const override { return new UnderLinePen(*this); }

private:
    void Line(const int length)const {
        for (int i = 0; i < length ; i++){
            cout << Emoji;
        }
    }

};

実行画面

@@@@@@@@@@@@@@
@ this is p1 @
@@@@@@@@@@@@@@
**************
* this is p2 *
**************
this is p3
__________
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2