C++で読むデザインパターン(Design Patterns read by C++)
「デスマーチと戦う武蔵流プログラマ やまざき のページ」

TopPage
(サイトマップ)


Book
(書籍)


「火事場プロジェクトの法則」
サポートページ


「LHAとZIP」
サポートページ



Document
(文章)

デスマーチの記録に見る
運命の分かれ道
NEW!

武蔵流プログラマからの提言

武蔵流プログラマが斬る Eclipse

コードデザイン最前線
1
2 3 4 5 6 7 8 9
10 11 12 13 ML

C++で読む
デザインパターン


ポインタ不要論

データ圧縮の基礎

プログラマへの
アドバイス


データ指向の話1 2

インターフェースの話


Diary & Books
(日記と本屋)

やまざきの
はてなダイアリ
(日記)
[] [PC] [資産運用]
[デスマ] [映画] [2足ロボ]

やまざきの本屋


SoftWorks
(ソフトウェア)


(1) DeepFreezer
(ディープ・フリーザー)
高速アーカイバ

(English Page)

(2) Closedown-Planet
(クローズダウン・プラネット)
アクションパズルゲーム


(3) PieceMaker
(ピース・メーカー)
ファイル分割/結合


(4) WakuPita
(枠ピタ)
ウィンドウ移動便利ツール

(English Page)

(5) ググ郎
(Bookmarklet)
選択文字列をGoogleで検索

NEW!


Developing
(開発中)


(1) DeepFreezer2
yz2dlg.dll alpha6


C Magazine特集yz2


Hobby & Favorite
(道楽/お気に入り)


2LegRobo
MindStorms



p.s.
(雑談)


Profile

i_want^^;


やまざきが書いた本


[システム開発]
火事場プロジェクトの法則
どうすればデスマーチをなくせるか?
2006/09/13 発売


LHAとZIP
圧縮アルゴリズム×プログラミング入門

奥村さんと共著です。
2003/12/01 発売


やまざきが寄稿した本


SEの読書術
「本質を読む」力を磨く10の哲学 2006/02発売。



開発の現場 Vol.002
「反デスマーチ大研究」という記事。2005/09/13発売。



Software People Vol.3
「武蔵流プログラマからの提言」という記事。2003/10/31発売。



Eclipse パーフェクトマニュアル vol.1
「武蔵流プログラマが斬る Eclipse」という記事。2003/06/05発売。




C++で読むデザインパターン(Design Patterns read by C++)



 デザインパターンの本って、眠い本が多いですね。^^; 「そんな薀蓄はいいから、コードで書いて見せてよ」という人(私)のために C++ のコードでデザインパターンを紹介します。とはいえ、やまざきの頭で解釈したことをそのままコードに書き出していますので、パターンの解釈の仕方が間違っているかもしれません。よって、これらのコードを鵜呑みにせず、各自 GoF 本などと照らし合わせて利用することをお薦めします。

 パターンは主にオブジェクト指向の「継承機能」を使って実装されますが、C++ のテンプレートやリファレンスを使うことで継承を使わなくても ある程度実装できるパターンがあります。その継承を使わないパターンを「非継承版」として掲載しています(個人的には継承という概念が嫌いなので^^;)。継承版と非継承版は同じ動作をします(実装方法が違う)のでコードを比べてみると良いと思います。まぁ、「非継承版」の方は お遊びのコードというか「こう書いてもいいじゃん」という、お試しのサンプルコードなのであまり本気にしないで下さい。
#非継承版って、実はジェネリックなコード(型に依存しないコード)であることに最近気が付きました。結構すごいことかも。

 全23パターンを C++ で書いてみて思ったことは「デザインパターン」とは「設計の定石」のことなんだと思いました。「ここはこんなパターンで構築できるね」とか、「ここのコードはxxxのパターンで書かれているね」という会話が出来るようになればデザインパターンの恩恵を受けてコードの生産性を上げられるのでしょう。
 なにかおかしなコードを発見した場合は連絡を下さい。これらのコードがみなさんのお役にたてば嬉しく思います。

あ、あと、このページをそのまま本にしませんか? この原稿を本にしてくれる出版社さんも募集しています。
こういう、シンプルなコードって、とっても重要だと思うのです。いやホントに。連絡をお待ちしています。
英語とか韓国語、中国語での出版も希望しています。
よろしくお願いします。
分類 パターン名 概要
構造 Adapter Adapter (非継承版) インターフェース(構造)の共通化
Bridge Bridge (非継承版) インターフェースを分離
Composite Composite (非継承版) 入れ物と入れるモノを同じインターフェース(構造)に
Decorator Decorator (非継承版) 同じインターフェース(構造)で拡張
Facade Facade (非継承版) 簡単なインターフェース(構造)を提供
Flyweight Flyweight (非継承版) インスタンスを共有
Proxy Proxy (非継承版) 代理(仲介者)を通す構造
振る舞い Chain of Responsibility Chain of Responsibility
(非継承版)
たらい回しする振る舞い
Command Command (非継承版) 実行部分を共通インターフェースに
Interpreter ミニ言語の構築
Iterator ←同梱 ポインタのような振る舞い
Mediator Mediator (非継承版) まとめ者のいる振る舞い
同→ Memento(非継承版) 情報をセーブする振る舞い
Observer Observer (非継承版) 観察者に知らされる振る舞い
State State(非継承版) 状態をインスタンスにする
Strategy Strategy (非継承版) アルゴリズムを入れ替える
TemplateMethod TemplateMethod
(非継承版)
一部の機能を後で実装する
Visitor Visitor (非継承版) 訪れて処理する振る舞い
生成 AbstractFactory AbstractFactory (非継承版) 抽象的な製品を生成する抽象的な工場
Builder Builder (非継承版) 生成過程を共通化
FactoryMethod FactoryMethod (非継承版) インスタンスの生成は後で実装
Prototype Prototype (非継承版) クローンを生成する
Singleton Singleton (非継承版) インスタンスを一つしか生成しない

[構造] Adapter パターン
共通インターフェイスを提供する。
#include <stdio.h> // puts()

// 既存のクラス(インターフェースがバラバラ)

class Apple
{
public:
    void AppleName()
    {
        puts( "りんご" ) ;
    }
    void AppleColor()
    {
        puts( "赤" ) ;
    }
} ;

class Banana
{
public:
    void BananaName()
    {
        puts( "バナナ" ) ;
    }
    void BananaColor()
    {
        puts( "黄" ) ;
    }
} ;

// Adapter パターン

// 共通インターフェースを作る
class AdapterPtn
{
public:
    virtual void  NamePuts()  = 0 ;
    virtual void  ColorPuts() = 0 ;
} ;

// 共通インターフェースにあわせる
class Apple2 : public AdapterPtn
{
    Apple  m_apple ;

public:
    virtual void NamePuts()
    {
        m_apple.AppleName() ;
    }
    virtual void ColorPuts()
    {
        m_apple.AppleColor() ;
    }
} ;

class Banana2 : public AdapterPtn
{
    Banana  m_banana ;

public:
    virtual void NamePuts()
    {
        m_banana.BananaName() ;
    }
    virtual void ColorPuts()
    {
        m_banana.BananaColor() ;
    }
} ;

// 実装
// ポインタで受け取るのは好きじゃないんだけど
void sub( AdapterPtn * in )
{
    // 共通インターフェースで呼べる
    in->NamePuts() ;
    in->ColorPuts() ;
}

int main()
{
    Apple2   a2 ; sub( & a2 ) ;
    Banana2  b2 ; sub( & b2 ) ;

    return 0 ;
}

/* 実行結果
りんご

バナナ

Press any key to continue
*/

[構造] Adapter パターン (非継承版)
共通インターフェイスを提供する。
#include <stdio.h> // puts()

// 既存のクラス(インターフェースがバラバラ)

class Apple
{
public:
    void AppleName()
    {
        puts( "りんご" ) ;
    }
    void AppleColor()
    {
        puts( "赤" ) ;
    }
} ;

class Banana
{
public:
    void BananaName()
    {
        puts( "バナナ" ) ;
    }
    void BananaColor()
    {
        puts( "黄" ) ;
    }
} ;

// Adapter パターン

// template の場合は、共通インターフェースを作る必要は無い。

// 共通インターフェースにあわせる
class Apple2
{
    Apple  m_apple ;

public:
    void NamePuts() // 共通インターフェース
    {
        m_apple.AppleName() ;
    }
    void ColorPuts() // 共通インターフェース
    {
        m_apple.AppleColor() ;
    }
} ;

class Banana2
{
    Banana  m_banana ;

public:
    void NamePuts() // 共通インターフェース
    {
        m_banana.BananaName() ;
    }
    void ColorPuts() // 共通インターフェース
    {
        m_banana.BananaColor() ;
    }
} ;

// 実装

templateclass _AdapterPtn >
void sub( _AdapterPtn & in )
{
    // 共通インターフェースで呼べる
    in.NamePuts() ;
    in.ColorPuts() ;
}

int main()
{
    Apple2   a2 ; sub( a2 ) ;
    Banana2  b2 ; sub( b2 ) ;

    return 0 ;
}

/* 実行結果
りんご

バナナ

Press any key to continue
*/

[構造] Bridge パターン
インターフェイスを2つに分けて橋渡し。それぞれ個別に拡張可能にする。
#include <stdio.h>  // printf()

// インターフェース(下部)
class BridgeLowPtn
{
public:
    virtual void  NamePuts() = 0 ; // 共通 Low インターフェース
} ;

// インターフェース(上部)
class BridgeHiPtn
{
public:
    BridgeLowPtn *  m_low ; // Low とつながっている

    BridgeHiPtn( BridgeLowPtn *  in ) // Low と結合
    : m_low( in )
    {}

    virtual void  Puts() = 0 ; // 共通 Hi インターフェース
} ;

// 実装

class Apple : public BridgeLowPtn
{
public:
    virtual void  NamePuts() // 共通 Low インターフェース
    {
        printf( "リンゴ" ) ;
    }
};

class Banana : public BridgeLowPtn
{
public:
    virtual void  NamePuts() // 共通 Low インターフェース
    {
        printf( "バナナ" ) ;
    }
};

class Hirosue : public BridgeHiPtn
{
public:
    Hirosue( BridgeLowPtn * in )
    : BridgeHiPtn( in )
    {}
    
    // Hi と Low のインターフェースを橋渡しする
    virtual void  Puts()     // 共通 Hi インターフェース
    {
        m_low->NamePuts() ;  // 共通 Low インターフェース
        printf( "をください\n" ) ;
    }
};

class Honjyo : public BridgeHiPtn
{
public:
    Honjyo( BridgeLowPtn * in )
    : BridgeHiPtn( in )
    {}
    
    // Hi と Low のインターフェースを橋渡しする
    virtual void  Puts()     // 共通 Hi インターフェース
    {
        m_low->NamePuts() ;  // 共通 Low インターフェース
        printf( "がほしいねん\n" ) ;
    }
};

void sub( BridgeLowPtn * in_fruit )
{
    Hirosue  ryoko( in_fruit ) ;
    ryoko.Puts() ;

    Honjyo  manami( in_fruit ) ;
    manami.Puts() ;
}

int main()
{
    Apple   apple ;  sub( & apple ) ;
    Banana  banana ; sub( & banana ) ;

    return 0 ;
}

/* 実行結果
リンゴをください
リンゴがほしいねん
バナナをください
バナナがほしいねん
Press any key to continue
*/

[構造] Bridge パターン (非継承版)
インターフェイスを2つに分けて橋渡し。それぞれ個別に拡張可能にする。
#include <stdio.h>  // printf()

// 実装

class Apple
{
public:
    void  NamePuts() // 共通 Low インターフェース
    {
        printf( "リンゴ" ) ;
    }
};

class Banana
{
public:
    void  NamePuts() // 共通 Low インターフェース
    {
        printf( "バナナ" ) ;
    }
};

templateclass _BridgeLowPtn >
class Hirosue
{
    _BridgeLowPtn &  m_low ;

public:
    Hirosue( _BridgeLowPtn & in )
    : m_low( in )
    {}
    
    // Hi と Low のインターフェースを橋渡しする
    void  Puts()            // 共通 Hi インターフェース
    {
        m_low.NamePuts() ;  // 共通 Low インターフェース
        printf( "をください\n" ) ;
    }
} ;

templateclass _BridgeLowPtn >
class Honjyo
{
    _BridgeLowPtn &  m_low ;

public:
    Honjyo( _BridgeLowPtn & in )
    : m_low( in )
    {}

    // Hi と Low のインターフェースを橋渡しする
    void  Puts()            // 共通 Hi インターフェース
    {
        m_low.NamePuts() ;  // 共通 Low インターフェース
        printf( "がほしいねん\n" ) ;
    }
};

templateclass _BridgeLowPtn >
void sub( _BridgeLowPtn & in_fruit )
{
    Hirosue< _BridgeLowPtn >  ryoko( in_fruit ) ;
    ryoko.Puts() ;  // 共通 Hi インターフェース

    Honjyo< _BridgeLowPtn >  manami( in_fruit ) ;
    manami.Puts() ;  // 共通 Hi インターフェース
}

int main()
{
    Apple   apple ;  sub( apple ) ;
    Banana  banana ; sub( banana ) ;

    return 0 ;
}

/* 実行結果
リンゴをください
リンゴがほしいねん
バナナをください
バナナがほしいねん
Press any key to continue
*/

[構造] Composite パターン
入れ物(器)と入れるモノを同じインターフェースにする。
木構造などの再起構造を使いたいときに使うパターン。
「枝」と「葉」に分けた場合、枝には枝と葉の両方を追加できる。
#include <stdio.h> // puts()
#include <string>  // STL  std::string

// Compositeパターン

class CompositePtn
{
public:
    std::string  m_name ;  // 名前

    CompositePtn( const std::string &  in_name )
    : m_name( in_name )
    {}

    // 共通インターフェース
    virtual void  Puts( const std::string &  in_parent ) = 0 ;
} ;

// 実装

// 葉
class Leaf : public CompositePtn
{
public:
    Leaf( const std::string &  in_name )
    : CompositePtn( in_name )
    {}

    // 共通インターフェース
    virtual void  Puts( const std::string &  in_parent )
    {
        std::string  str = in_parent + "/" + m_name ;

        puts( str.c_str() ) ;
    }
} ;

// 葉(終端)
class Null : public CompositePtn
{
public:
    Null()
    : CompositePtn( "" )
    {}

    // 共通インターフェース
    virtual void  Puts( const std::string &  in_parent )
    {}
} ;

// 枝
class Tree : public CompositePtn
{
    // std::vector<CompositePtn *> tbl ; でも可
    CompositePtn *  m_left ;  // 左の枝
    CompositePtn *  m_right ; // 右の枝

public:
    Tree(
        const std::string &  in_name,
        CompositePtn *       in_left,
        CompositePtn *       in_right
    )
    : CompositePtn( in_name )
    , m_left(  in_left  )
    , m_right( in_right )
    {}
    
    // 共通インターフェース
    virtual void  Puts( const std::string &  in_parent )
    {
        std::string  str = in_parent + "/" + m_name ;

        puts( str.c_str() ) ;

        // 枝をたどる
        m_left->Puts( str ) ;
        m_right->Puts( str ) ;
    }
};


int main()
{
    // honjyo には apple と banana
    Leaf  apple( "apple" ) ;
    Leaf  banana( "banana" ) ;
    Tree  honjyo( "honjyo", &apple, &banana ) ;

    // hirosue には cacao だけ
    Leaf  cacao( "cacao" ) ;
    Null  null ;
    Tree  hirosue( "hirosue", &cacao, &null ) ;

    // 木の根っこ
    // 左の枝には honjyo 右の枝には hirosue
    Tree  root( "root", &honjyo, &hirosue ) ;

    // 全部表示してみましょう。
    root.Puts( "" ) ;

    return  0 ;
}

/* 実行結果
/root
/root/honjyo
/root/honjyo/apple
/root/honjyo/banana
/root/hirosue
/root/hirosue/cacao
Press any key to continue
*/



[構造] Composite パターン(非継承版)
入れ物(器)と入れるモノを同じインターフェースにする。
木構造などの再起構造を使いたいときに使うパターン。
「枝」と「葉」に分けた場合、枝には枝と葉の両方を追加できる。
#include <stdio.h> // puts()
#include <string>  // STL  std::string

// Compositeパターン

// 実装

// 葉
class Leaf
{
    const std::string  m_name ;

public:
    Leaf( const std::string  in_name )
    : m_name( in_name )
    {}

    // 共通インターフェース
    void  Puts( const std::string &  in_parent )
    {
        std::string  str = in_parent + "/" + m_name ;

        puts( str.c_str() ) ;
    }
} ;

// 葉(終端)
class Null
{
public:
    Null(){}

    // 共通インターフェース
    void  Puts( const std::string &  in_parent )
    {}
} ;

// 枝
templateclass _Left, class _Right >
class Tree
{
    const std::string  m_name ;

    _Left &   m_left ;  // 左の枝
    _Right &  m_right ; // 右の枝

public:
    Tree(
        const std::string  in_name,
        _Left &            in_left,
        _Right &           in_right
    )
    : m_name(  in_name )
    , m_left(  in_left )
    , m_right( in_right )
    {}
    
    // 共通インターフェース
    void  Puts( const std::string &  in_parent )
    {
        std::string  str = in_parent + "/" + m_name ;

        puts( str.c_str() ) ;

        // 枝をたどる
        m_left.Puts( str ) ;
        m_right.Puts( str ) ;
    }
};


int main()
{
    // honjyo には apple と banana
    Leaf                apple( "apple" ) ;
    Leaf                banana( "banana" ) ;
    Tree< Leaf, Leaf >  honjyo( "honjyo", apple, banana ) ;

    // hirosue には cacao だけ
    Leaf                cacao( "cacao" ) ;
    Null                null ;
    Tree< Leaf, Null >  hirosue( "hirosue", cacao, null ) ;

    // 木の根っこ
    // 左の枝には honjyo 右の枝には hirosue
    // なんか、すでに保守できないくらい複雑になっている^^;
    Tree< Tree< Leaf, Leaf >, Tree< Leaf, Null > >
        root( "root", honjyo, hirosue ) ;

    // 全部表示してみましょう。
    root.Puts( "" ) ;

    return  0 ;
}

/* 実行結果
/root
/root/honjyo
/root/honjyo/apple
/root/honjyo/banana
/root/hirosue
/root/hirosue/cacao
Press any key to continue
*/

[構造] Decorator パターン
同じインターフェースで拡張するイメージ。機能を付加(飾り付け)するパターン。
#include <stdio.h> // puts()

// Decoratorパターン

class DecoratorPtn
{
public:
    virtual void  Puts() = 0 ; // インターフェース
} ;

// 実装

class Apple : public DecoratorPtn
{
public:
    virtual void  Puts() // インターフェース
    {
        puts( "リンゴ" ) ;
    }
} ;

class Banana : public DecoratorPtn
{
public:
    virtual void  Puts() // インターフェース
    {
        puts( "バナナ" ) ;
    }
};

class Good : public DecoratorPtn
{
    DecoratorPtn *  m_p_decorator ;

public:
    Good( DecoratorPtn* in )
    : m_p_decorator( in )
    {}
    
    virtual void Puts()   // 拡張インターフェース
    {
        printf( "おいしい" ) ;
        m_p_decorator->Puts() ; // オリジナルを呼ぶ
    }
} ;

void sub( DecoratorPtn* in )
{
    in->Puts() ;

    // 拡張その1
    Good  good( in ) ;
    good.Puts() ;

    // 拡張その2
    Good  verygood( & good ) ;
    verygood.Puts() ;
}

int main()
{
    Apple   apple ;  sub( & apple ) ;
    Banana  banana ; sub( & banana ) ;

    return  0 ;
}

/* 実行結果
リンゴ
おいしいリンゴ
おいしいおいしいリンゴ
バナナ
おいしいバナナ
おいしいおいしいバナナ
Press any key to continue
*/

[構造] Decorator パターン (非継承版)
同じインターフェースで拡張するイメージ。機能を付加(飾り付け)するパターン。
#include <stdio.h> // puts()

// Decoratorパターン

// 実装

class Apple
{
public:
    void  Puts()  // インターフェース
    {
        puts( "リンゴ" ) ;
    }
} ;

class Banana
{
public:
    void  Puts()  // インターフェース
    {
        puts( "バナナ" ) ;
    }
};

templateclass _DecoratorPtn >
class Good 
{
    _DecoratorPtn &  m_decorator ;

public:
    Good( _DecoratorPtn & in  )
    : m_decorator( in )
    {}

    void Puts()   // 拡張インターフェース
    {
        printf( "おいしい" ) ;
        m_decorator.Puts() ; // オリジナルを呼ぶ
    }
} ;

templateclass _ObjectPtn >
void sub( _ObjectPtn in )
{
    in.Puts() ;

    // 拡張その1
    Good< _ObjectPtn >  good( in ) ;
    good.Puts() ;

    // 拡張その2
    Good< Good< _ObjectPtn > >  verygood( good ) ;
    verygood.Puts() ;
}

int main()
{
    Apple   apple ;  sub( apple ) ;
    Banana  banana ; sub( banana ) ;

    return  0 ;
}

/* 実行結果
リンゴ
おいしいリンゴ
おいしいおいしいリンゴ
バナナ
おいしいバナナ
おいしいおいしいバナナ
Press any key to continue
*/

[構造] Facade パターン
複雑な処理を簡単なインターフェースで提供する。
#include <stdio.h> // printf()

// もともとある実装(本当はもっと複雑なクラスだと思われ^^;)

class Apple
{
public:
    int value_Get()
    {
        return 120 ;
    }
} ;

class Banana
{
public:
    int value_Get()
    {
        return 60 ;
    }
} ;

// Facadeパターンだけど、パターンと言えるのかね。

class FacadePtn
{
public:
    virtual void  Shopping() = 0 ; // 簡単なメソッド
} ;

// 実装

class Hirosue : public FacadePtn
{
public:
    virtual void  Shopping()
    {
        // 複雑な処理?を隠す
        Apple   apple ;
        Banana  banana ;
        int     val = 0 ;

        val += apple.value_Get()  * 2 ; // リンゴ2個
        val += banana.value_Get() * 3 ; // バナナ3個

        printf( "%d円じゃん。\n", val ) ;
    }
} ;

class Honjyo : public FacadePtn
{
public:
    virtual void  Shopping()
    {
        // 複雑な処理?を隠す
        Banana  banana ;
        int     val = banana.value_Get() * 50 ; // バナナ50個

        printf( "%d円やねん。\n", val ) ;
    }
} ;

void sub( FacadePtn * in )
{
    in->Shopping() ;
}

int main()
{
    Hirosue  ryoko ; sub( & ryoko ) ;
    Honjyo  manami ; sub( & manami ) ;

    return 0 ;
}

/* 実行結果
420円じゃん。
3000円やねん。
Press any key to continue
*/

[構造] Facade パターン (非継承版)
複雑な処理を簡単なインターフェースで提供する。
// Facade パターン (template版)

// 複雑な処理を簡単にする。 

#include <stdio.h> // printf()

// もともとある実装(本当はもっと複雑なクラスだと思われ^^;)

class Apple
{
public:
    int value_Get()
    {
        return 120 ;
    }
} ;

class Banana
{
public:
    int value_Get()
    {
        return 60 ;
    }
} ;

// Facadeパターンだけど、パターンと言えるのかね。

// 実装

class Hirosue
{
public:
    void  Shopping()
    {
        // 複雑な処理?を隠す
        Apple   apple ;
        Banana  banana ;
        int     val = 0 ;

        val += apple.value_Get()  * 2 ; // リンゴ2個
        val += banana.value_Get() * 3 ; // バナナ3個

        printf( "%d円じゃん。\n", val ) ;
    }
} ;

class Honjyo
{
public:
    void  Shopping()
    {
        // 複雑な処理?を隠す
        Banana  banana ;
        int     val = banana.value_Get() * 50 ; // バナナ50個

        printf( "%d円やねん。\n", val ) ;
    }
} ;

templateclass _FacadePtn >
void sub( _FacadePtn & in )
{
    in.Shopping() ;
}

int main()
{
    Hirosue  ryoko ; sub( ryoko ) ;
    Honjyo  manami ; sub( manami ) ;

    return 0 ;
}

/* 実行結果
420円じゃん。
3000円やねん。
Press any key to continue
*/

[構造] Flyweight パターン
インスタンスを共有してメモリを軽くする。キャッシュのような考え方だと思う。
Proxy の配列版とも言えるかも。
#include <stdio.h> // printf()

// Flyweight パターン

class FlyweightPtn
{
public:
    virtual void Puts() = 0 ;
} ;

// 実装

class Apple : public FlyweightPtn
{
    char * m_str ;

public:
    Apple()
    {
        // もっとメモリを沢山必要とするclassだと思われ
        m_str = "+--------+\n| リンゴ |\n+--------+" ;
    }

    virtual void Puts()
    {
        puts( m_str ) ;
    }
} ;

class Banana : public FlyweightPtn
{
    char * m_str ;

public:
    Banana()
    {
        // もっとメモリを沢山必要とするclassだと思われ
        m_str = "onnnnnnnno\n8 バナナ 8\n8uuuuuuuu8" ;
    }

    virtual void Puts()
    {
        puts( m_str ) ;
    }
} ;

class FlyweightFactory
{
    // インスタンス化するのは2つ
    Apple           m_apple ;
    Banana          m_banana ;
    FlyweightPtn *  m_p_tbl[4] ;

public:
    FlyweightFactory()
    {
        // 4つ分のインスタンス(メモリ)を2つ分に減らす。
        m_p_tbl[0] = & m_apple ;
        m_p_tbl[1] = & m_apple ;
        m_p_tbl[2] = & m_banana ;
        m_p_tbl[3] = & m_banana ;
    }

    void Put( int in )
    {
        m_p_tbl[ in % 4 ]->Puts() ;
    }
} ;


int main()
{
    FlyweightFactory  factory ;

    for ( int i=0 ; i<6 ; ++i )
    {
        factory.Put( i ) ;
    }

    return  0 ;
}

/* 実行結果
+--------+
| リンゴ |
+--------+
+--------+
| リンゴ |
+--------+
onnnnnnnno
8 バナナ 8
8uuuuuuuu8
onnnnnnnno
8 バナナ 8
8uuuuuuuu8
+--------+
| リンゴ |
+--------+
+--------+
| リンゴ |
+--------+
Press any key to continue
*/


[構造] Flyweight パターン(非継承版)
template ではできないね。
インスタンスを共有してメモリを軽くする。キャッシュのような考え方だと思う。
Proxy の配列版とも言えるかも。
#include <stdio.h> // printf()

// Flyweight パターン(非継承版)

// 実装
class Apple
{
    char * m_str ;

public:
    Apple()
    {
        // もっとメモリを沢山必要とするclassだと思われ
        m_str = "+--------+\n| リンゴ |\n+--------+" ;
    }

    virtual void Puts()
    {
        puts( m_str ) ;
    }
} ;

class Banana
{
    char * m_str ;

public:
    Banana()
    {
        // もっとメモリを沢山必要とするclassだと思われ
        m_str = "onnnnnnnno\n8 バナナ 8\n8uuuuuuuu8" ;
    }

    virtual void Puts()
    {
        puts( m_str ) ;
    }
} ;

class FlyweightFactory
{
    // インスタンス化するのは2つ
    Apple   m_apple ;
    Banana  m_banana ;

public:
    void Put( int in )
    {
        // 4つ分のインスタンス(メモリ)を2つ分に減らす。
        // わざわざパターンにしなくても switch で良いと思うのだけど
        // 数が多くなるとたいへんだけどね。^^;
        switch( in % 4 )
        {
            case 0 : m_apple.Puts() ; break ;
            case 1 : m_apple.Puts() ; break ;
            case 2 : m_banana.Puts() ; break ;
            case 3 : m_banana.Puts() ; break ;
        }
    }
} ;


int main()
{
    FlyweightFactory  factory ;

    for ( int i=0 ; i<6 ; ++i )
    {
        factory.Put( i ) ;
    }

    return  0 ;
}
/* 実行結果
+--------+
| リンゴ |
+--------+
+--------+
| リンゴ |
+--------+
onnnnnnnno
8 バナナ 8
8uuuuuuuu8
onnnnnnnno
8 バナナ 8
8uuuuuuuu8
+--------+
| リンゴ |
+--------+
+--------+
| リンゴ |
+--------+
Press any key to continue
*/



[構造] Proxy パターン
代理(仲介者)を通すパターン。これは分かりやすいし簡単だよね。
キャッシュのパターンにも使える。
Decorator にも似ているが、Proxy は機能拡張をしない。
#include <stdio.h>

// Proxyパターン
// オリジナルも代理も同じインターフェースを使う

class ProxyPtn
{
public:
    virtual void  Eat() = 0 ;
} ;

// 実装 オリジナル

class Apple : public ProxyPtn
{
public:
    Apple()
    {
        puts( "リンゴを買う。" ) ;
    }

    virtual void  Eat()
    {
        puts( "あー、おいしい。" ) ;
    }
} ;

// 実装 代理

class AppleProxy : public ProxyPtn
{
    Apple *  m_p_apple ;

public:
    AppleProxy()
    : m_p_apple( 0 ) // 必要になるまで作らないことにする
    {}

    ~AppleProxy()
    {
        if ( m_p_apple != 0 )
        {
            delete m_p_apple ;
            m_p_apple = 0 ;
        }
    }

    virtual void  Eat()
    {
        if ( m_p_apple == 0 )
        {
            // 無いので作る
            m_p_apple = new Apple ;
        }
        m_p_apple->Eat() ;
    }
} ;

int main()
{
    puts( "----オリジナル-----" ) ;
    {
        Apple  apple1 ;
        Apple  apple2 ;
        Apple  apple3 ;

        // 3つ買ったけど、食べるのは1つ
        apple1.Eat() ;
        apple1.Eat() ;
    }

    puts( "----代理-----" ) ;
    {
        AppleProxy  proxy1 ;
        AppleProxy  proxy2 ;
        AppleProxy  proxy3 ;

        // 3つ買ったけど、食べるのは1つ
        proxy1.Eat() ;
        proxy1.Eat() ;
    }

    return  0 ;
}

/* 実行結果
----オリジナル-----
リンゴを買う。
リンゴを買う。
リンゴを買う。
あー、おいしい。
あー、おいしい。
----代理-----
リンゴを買う。
あー、おいしい。
あー、おいしい。
Press any key to continue
*/

[構造] Proxy パターン (非継承版)
代理(仲介者)を通すパターン。これは分かりやすいし簡単だよね。
キャッシュのパターンにも使える。
Decorator にも似ているが、Proxy は機能拡張をしない。
#include <stdio.h>
#include <vector>  // std::vector
 
// Proxyパターン

// 実装 オリジナル

class Apple
{
public:
    Apple()
    {
        puts( "リンゴを買う。" ) ;
    }

    void  Eat()
    {
        puts( "あー、おいしい。" ) ;
    }
} ;

// 実装 代理

class AppleProxy
{
    // std::vector を使って強引に構築してみました。
    // 効率的とは言い難いが、ま、ご参考ってことで。^^;
    std::vector< Apple >  m_apple ;

public:
    virtual void  Eat()
    {
        if ( m_apple.size() == 0 )
        {
            // コピーコンストラクタも動いちゃうけどね
            m_apple.resize( 1 ) ;
        }
        m_apple[0].Eat() ;
    }
} ;

int main()
{
    puts( "----オリジナル-----" ) ;
    {
        Apple  apple1 ;
        Apple  apple2 ;
        Apple  apple3 ;

        // 3つ買ったけど、食べるのは1つ
        apple1.Eat() ;
        apple1.Eat() ;
    }

    puts( "----代理-----" ) ;
    {
        AppleProxy &n