条款19 command 模式与好莱坞法则
当一个函数对象被当做回调时候,就是一个command模式的实例
什么是回调? 回调就是框架知道什么时候干一些事情,但是具体干什么,或许框架一无所知(因为回调函数不是他设计的),而用户则知道发生一个特定事件的时候,应该干什么,但是他不知道什么时候去干这个事情。这两个部分共同构成了一个完整的应用程序。
常见的回调函数的实现方式是函数指针,类似如下的方式:
extern void playmusic();
//。。。
button * new Button(“anko no nama”);
b->setAction( playmusic);
registerButtonWithFramework(b);
但是现实中我们可能有这样的需求,设计播放的歌曲,他所使用的编码,和解码器等等, 一个比较好的方式是利用函数对象代替函数指针。
使用这个方式有一个显而易见的好处,函数对象可以封装数据,同时函数对象可以虚拟成员表现出动态行为。
1: class Action
2: {
3: public:
4: virtual ~Action();
5: virtual void operation()()=0;
6: virtual Action *clone() const = 0; //原型(prototype);
7: }
8:
9: class Button
10:
11: {
12:
13: public:
14: Button(const std::string &label ): label_( label),action_(0){}
15: void setAction(const Action *newAction)
16: {
17: Action *temp = newAction.clone();
18: delete action_;
19: action_ = temp;
20: }
21:
22: void onClick() const
23: {
24: if( action_ ) (*action)();
25: }
26: private:
27: std::string label_;
28: Action *action;
29: }
30:
31: class PlayMusic : public Action
32: {
33: public:
34: PlayMusic( const string &songFile ):song_(songFile){}
35: void operator ()();
36: Action *clone();
37: private:
38: MP3 song_;
39: }
40:
被封装的数据既保持了playmusic的函数对象的灵活性,有保持了他的安全性;
1: Button *b = new Button( “anoko no nama” );
2: auto_ptr<PlayMusic> song( ne PlayMusic(“anokononama.mp3”));
3: b->setAction( song.get)
可以看做是函数对象的又一个比较好的应用;