- 观察者模式
信号(被观察者)-> 槽(观察者)
以一个Button多个动作为例:
- 基本代码
需要在编写Button时就将各种action的可能性列出,即代码耦合太大,编写时就要考虑引入其他对象
- 纯虚函数
只需编写一个Button基类,通过继承得到不同action的Button类,即通过继承对象实现重用,但由于是对Button类的扩展,也不是很方便
- 回调函数
编写一个Button结构体,通过函数指针指向不同的action,即通过函数指针实现重用,但在运行时才传参而且没有类型安全的检查(为了通一函数接口,函数指针的入参设置为void*,不同的动作需要不同的强制转换),这是极不安全的
#include <stdio.h>
void reloadPage()
{
printf("reloadPage\n");
}
void loadPage(char *url)
{
printf("%s\n",url);
}
void reloadPage_action(void* arg)
{
reloadPage();
}
void loadPage_action(void* url)
{
loadPage((char*)url);
}
struct Button
{
void (*actionFunc_)(void*);//函数指针,只是个指针因此在c中struct可以定义
void* actionFuncData_;
};
void buttonClicked(Button* button)
{
if(button && button->actionFunc_)
(*button->actionFunc_)(button->actionFuncData_);
}
int main(int argc, char *argv[])
{
Button iButton;
char* tmp = "loadPage";
iButton.actionFuncData_ = tmp;
iButton.actionFunc_ = loadPage_action;
buttonClicked(&iButton);
printf("Hello World!\n");
return 0;
}
- 构建抽象action
在Button类中定义一个指向action基类的指针,通过继承action基类实现action的多态,使用基类的指针指向不同的action类
#include <iostream>
class BaseAction
{
public:
virtual void execute()=0;
};
class PageLoadAction : public BaseAction
{
public:
virtual void execute()
{
std::cout << "PageLoadAction" << std::endl;
}
};
class PageReloadAction : public BaseAction
{
public:
virtual void execute()
{
std::cout << "PageReloadAction" << std::endl;
}
};
class Button
{
public:
BaseAction* iBaseAction;
void clicked()
{
if(iBaseAction)
iBaseAction->execute();
}
};
int main()
{
Button iButton;
iButton.iBaseAction = new PageReloadAction;
iButton.clicked();
return 0;
}
- 多对多
通过链表添加多个action
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/function.hpp>
#include <boost/bind.hpp>
class BaseAction
{
public:
virtual void execute()=0;
};
class PageLoadAction : public BaseAction
{
public:
virtual void execute()
{
std::cout << "PageLoadAction" << std::endl;
}
};
class PageReloadAction : public BaseAction
{
public:
virtual void execute()
{
std::cout << "PageReloadAction" << std::endl;
}
};
class MultiAction : public BaseAction
{
public:
virtual void execute()
{
std::for_each(actionList.begin(),actionList.end(),\
boost::bind(&BaseAction::execute,_1));//bind绑定参数
}
void addAction(BaseAction* action_)
{
actionList.push_back(action_);
}
MultiAction()
{
}
~MultiAction()
{
actionList.clear();
}
private:
std::vector<BaseAction*> actionList;
};
class Button
{
public:
BaseAction* iBaseAction;
void clicked()
{
if(iBaseAction)
iBaseAction->execute();
}
};
int main()
{
MultiAction* piMultiAction = new MultiAction;
PageLoadAction* piPageLoadAction = new PageLoadAction;
PageReloadAction* piPageReloadAction = new PageReloadAction;
piMultiAction->addAction(piPageLoadAction);
piMultiAction->addAction(piPageReloadAction);
Button* piButton = new Button;
piButton->iBaseAction = piMultiAction;
piButton->clicked();
return 0;
}
- 函数对象
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/function.hpp>
#include <boost/bind.hpp>
class BaseAction
{
public:
virtual void operator()() = 0;
};
class PageLoadAction : public BaseAction
{
public:
virtual void operator()()
{
std::cout << "PageLoadAction" << std::endl;
}
};
class PageReloadAction : public BaseAction
{
public:
virtual void operator()()
{
std::cout << "PageReloadAction" << std::endl;
}
};
class MultiAction : public BaseAction
{
public:
virtual void operator()()
{
std::for_each(actionList.begin(),actionList.end(),\
boost::bind(&BaseAction::operator(),_1));
}
void addAction(BaseAction* action_)
{
actionList.push_back(action_);
}
MultiAction()
{
}
~MultiAction()
{
actionList.clear();
}
private:
std::vector<BaseAction*> actionList;
};
class Button
{
public:
BaseAction* piBaseAction;
void clicked()
{
if(piBaseAction)
piBaseAction->operator ()();//option 2: call the function by its new name
//(*piBaseAction)();//option 1: use the dereferenced pointer like a function
}
};
int main()
{
MultiAction* piMultiAction = new MultiAction;
PageLoadAction* piPageLoadAction = new PageLoadAction;
PageReloadAction* piPageReloadAction = new PageReloadAction;
piMultiAction->addAction(piPageLoadAction);
piMultiAction->addAction(piPageReloadAction);
Button* piButton = new Button;
piButton->piBaseAction = piMultiAction;
piButton->clicked();
return 0;
}
- Boost.Signals
Boost.Signals 库具体化了信号(signals)和插槽(slots),信号指的是某种可被”抛出”的东西,而插槽是接收该信号的连接者。这是一种著名的设计模式,它还有另外一些名字 Observer, signals/slots, publisher/subscriber, events (和 event targets),这些名字指的都是同一个东西,指的是一些信息源和某些对这些信息的变化感兴趣的实例之间的一对多关系。注意:使用时需要添加链接库LIBS += -lboost_signals
,否则会出现如下错误:undefined reference to 'boost::signals::connection::~connection()'
#include <iostream>
#include "boost/signals.hpp"
#include "boost/bind.hpp"
typedef void(*Func)();
void ShowPage()
{
std::cout << "Show Page" << std::endl;
}
class Button
{
public:
boost::signal<void()>clicked;
};
class Page
{
public:
void reload()
{
std::cout << "reload" << std::endl;
}
void operator ()()
{
std::cout << "Page load" << std::endl;
}
};
int main()
{
Page iPage;
Func f = ShowPage;
Button* piButton = new Button;
piButton->clicked.connect(f);//函数指针
piButton->clicked.connect(ShowPage);//函数
piButton->clicked.connect(Page());//函数对象
piButton->clicked.connect(boost::bind(&Page::reload,iPage));//类成员
piButton->clicked();
return 0;
}
- 备注
本文参考链接