当前位置: 首页 > 工具软件 > QuteCom > 使用案例 >

QuteCom手记:使用Event类实现观察者模式

仉洲
2023-12-01

Event类的定义在qutecom\libs\owutil\util\event.h

	/**
	 * Connects a slot to this signal (=event).
	 *
	 * Provides unicity when connecting a slot to a signal.
	 * Two identical slots cannot be connected, only one will be:
	 * this method checks first if the same slot was not connected already.
	 *
	 * @param slot callback function
	 * @return connection object
	 */
	template<typename Slot>
	boost::signals::connection operator+=(const Slot & slot) {
		boost::signals::connection c;
		if (!alreadyConnected(slot)) {
			//The slot is not connected to the signal
			c = this->connect(slot);
			SlotConnection sc;
			sc.connection = c;
			sc.slot = slot;
			_slotList.push_back(sc);
		}
		//The slot is already connected to the signal
		return c;
	}

	/**
	 * Connects a signal to another signal (=event).
	 *
	 * Does not check if the signal is already connected, does not
	 * provide unicity connection.
	 *
	 * @param event signal to connect
	 * @return connection object
	 */
	boost::signals::connection operator+=(const Event & event) {
		return this->connect(event);
	}

	/**
	 * Disconnects a slot from a signal (=event).
	 *
	 * Slot comparison does not always work properly,
	 * check http://boost.org/doc/html/function/faq.html#id2699084
	 *
	 * @param slot callback function to disconnect from the signal
	 */
	template<typename Slot>
	void operator-=(const Slot & slot) {
		typename SlotList::iterator it;
		for (it = _slotList.begin(); it != _slotList.end(); it++) {
			if ((*it).slot == slot)
				break;
		}
		if (it != _slotList.end()) {
			(*it).connection.disconnect();
			_slotList.erase(it);
		}
	}


Event继承了 boost::signal,重载了-=和+=运算符。分别对应boost::signal的disconncet和connect。

Event在PhoneCall类中的使用:

qutecom\qutecom\src\model\phonecall\phonecall.h

	/**
	 * The state of the PhoneCall has changed.
	 *
	 * @param sender this class
	 * @param status new status
	 */
	Event<void (PhoneCall & sender, EnumPhoneCallState::PhoneCallState status)> stateChangedEvent;

	/**
	 * A video frame has been received from the network.
	 *
	 * @param sender this class
	 * @param remoteVideoFrame remote video frame
	 * @param localVideoFrame local video frame from the webcam
	 */
	Event<void (PhoneCall & sender, piximage * remoteVideoFrame, piximage * localVideoFrame)> videoFrameReceivedEvent;

stateChangedEvent的声明说明函数对象的原型为void (PhoneCall & sender, EnumPhoneCallState::PhoneCallState status),无返回值,第一个参数为PhoneCall对象的引用,第二个参数为一个状态码。

stateChangedEvent事件的“事件处理函数”设置:

 

void CPhoneCall::initPresentationThreadSafe() {
	_pPhoneCall = PFactory::getFactory().createPresentationPhoneCall(*this);

	_phoneCall.stateChangedEvent += boost::bind(&CPhoneCall::stateChangedEventHandler, this, _1, _2);
	_phoneCall.videoFrameReceivedEvent += boost::bind(&CPhoneCall::videoFrameReceivedEventHandler, this, _1, _2, _3);
}

注意boost::bind的第二参数为this指针而不能为对象,这是因为CPhoneCall的实例是不可复制对象。见CPhoneCall的声明。

 

stateChangedEvent事件的触发:

void PhoneCall::setState(EnumPhoneCallState::PhoneCallState state) {
	LOG_DEBUG("PhoneCallState=" + String::fromNumber(state));

	for (unsigned i = 0; i < _phoneCallStateList.size(); i++) {
		PhoneCallState * callState = _phoneCallStateList[i];
		if (callState->getCode() == state) {
			if (_state->getCode() != callState->getCode()) {
				_state = callState;
				//省略......
				LOG_DEBUG("call state changed callId=" + String::fromNumber(_callId) +
					" state=" + EnumPhoneCallState::toString(_state->getCode()));
				applyState(state);
				stateChangedEvent(*this, state);
				return;
			}
		}
	}

	//LOG_FATAL("unknown PhoneCallState=" + String::fromNumber(state));
}

当模型PhoneCall的实例发生状态改变时,将触发stateChangedEvent。第一参数为PhoneCall实例引用,第二参数为状态代码。由此将调用对应CPhoneCall对应实例的stateChangedEventHandler函数,并将两个参数传递给它。

注意他们在同一上下文中执行。

Event用这种方法实现了观察者模式,CPhoneCall是观察者,PhoneCall是被观察模型。

还有CPhoneLine和PhoneLine也是如此。

 

关于boost::bind的文章请见: 

http://blog.csdn.net/Solstice/article/details/3066268

http://www.cppblog.com/shanoa/archive/2009/06/15/87746.aspx

 类似资料: