|
C++で読むデザインパターン(Design Patterns read by C++)
デザインパターンの本って、眠い本が多いですね。^^; 「そんな薀蓄はいいから、コードで書いて見せてよ」という人(私)のために C++ のコードでデザインパターンを紹介します。とはいえ、やまざきの頭で解釈したことをそのままコードに書き出していますので、パターンの解釈の仕方が間違っているかもしれません。よって、これらのコードを鵜呑みにせず、各自 GoF 本などと照らし合わせて利用することをお薦めします。
パターンは主にオブジェクト指向の「継承機能」を使って実装されますが、C++
のテンプレートやリファレンスを使うことで継承を使わなくても ある程度実装できるパターンがあります。その継承を使わないパターンを「非継承版」として掲載しています(個人的には継承という概念が嫌いなので^^;)。継承版と非継承版は同じ動作をします(実装方法が違う)のでコードを比べてみると良いと思います。まぁ、「非継承版」の方は
お遊びのコードというか「こう書いてもいいじゃん」という、お試しのサンプルコードなのであまり本気にしないで下さい。
#非継承版って、実はジェネリックなコード(型に依存しないコード)であることに最近気が付きました。結構すごいことかも。
全23パターンを C++ で書いてみて思ったことは「デザインパターン」とは「設計の定石」のことなんだと思いました。「ここはこんなパターンで構築できるね」とか、「ここのコードはxxxのパターンで書かれているね」という会話が出来るようになればデザインパターンの恩恵を受けてコードの生産性を上げられるのでしょう。
なにかおかしなコードを発見した場合は連絡を下さい。これらのコードがみなさんのお役にたてば嬉しく思います。
あ、あと、このページをそのまま本にしませんか? この原稿を本にしてくれる出版社さんも募集しています。
こういう、シンプルなコードって、とっても重要だと思うのです。いやホントに。連絡をお待ちしています。
英語とか韓国語、中国語での出版も希望しています。
よろしくお願いします。
| [構造] 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() ;
}
} ;
// 実装
template< class _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( "バナナ" ) ;
}
};
template< class _BridgeLowPtn >
class Hirosue
{
_BridgeLowPtn & m_low ;
public:
Hirosue( _BridgeLowPtn & in )
: m_low( in )
{}
// Hi と Low のインターフェースを橋渡しする
void Puts() // 共通 Hi インターフェース
{
m_low.NamePuts() ; // 共通 Low インターフェース
printf( "をください\n" ) ;
}
} ;
template< class _BridgeLowPtn >
class Honjyo
{
_BridgeLowPtn & m_low ;
public:
Honjyo( _BridgeLowPtn & in )
: m_low( in )
{}
// Hi と Low のインターフェースを橋渡しする
void Puts() // 共通 Hi インターフェース
{
m_low.NamePuts() ; // 共通 Low インターフェース
printf( "がほしいねん\n" ) ;
}
};
template< class _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 )
{}
} ;
// 枝
template< class _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( "バナナ" ) ;
}
};
template< class _DecoratorPtn >
class Good
{
_DecoratorPtn & m_decorator ;
public:
Good( _DecoratorPtn & in )
: m_decorator( in )
{}
void Puts() // 拡張インターフェース
{
printf( "おいしい" ) ;
m_decorator.Puts() ; // オリジナルを呼ぶ
}
} ;
template< class _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 ) ;
}
} ;
template< class _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 | | |