boost::signals::signal的用法

吃力的講完boost::signals的ppt,然後接着就是做練習題。通過講ppt,發現有一句話說的真好:你自己知道是一回事,你能給別人講明白又是另外一回事。真的有些東西你自己理解,但是用語言去很難表達,是不是用語言難以表達暴露出自己對所理解的東西不是真正的理解?。。。。orz,不過講完ppt之後,真的對boost::singals的理解又加深一層。好了廢話不多說了,現在來看兩個習題(ppt的內容基本上是boost官方網站介紹boost::singlas用法的章節,這裏不貼了):

第一題:

題目1:實現一個日常生活裏出現的情景

描述:

     客人按門鈴,門鈴響,護士開門,嬰兒驚醒後苦惱。

要求:

     有至少兩個護士和兩個嬰兒,並且某護士去開門是一個隨機事件(隨機數),只有當滿足某個條件時纔去開門,比如隨機數randX滿足500<randX%1000<999的時候纔去開門,當然如果有一個護士去開門,剩下的護士就不用去開門了!門鈴響,某個嬰兒被驚醒也是一個隨機事件,當滿足一定條件時,這個嬰兒醒來就哭叫,沒醒的繼續睡覺_~~_。

這個題就是想實現一個簡單的觀察這模式,如果不用boost::signals來實現,我們就得按照觀察模式來寫,首先肯定有一個觀察者的基類,然後是n多派生觀察者;其次要定義一個被觀察者基類,然後就是m多被觀察者,下面是一個實現:

<span style="font-size:14px;">namespace TestRing 
{
	//觀察者基類
	class CPerson
	{
	public:
		CPerson(const std::string& vName) : m_Name(vName) {}
		virtual ~CPerson()                {}

		//觀察者收到通知(觸發信號)的動作
		virtual void act()                
		{
			std::cout<<"no action \n";
		}
		const std::string getName() const {return m_Name;}

	private:
		std::string m_Name;
	};

	//一個派生子類,實際觀察者
	class CNurse : public CPerson
	{
	public:
		CNurse(const std::string& vName) : CPerson(vName) {}

		virtual void act() {std::cout<<"Nurse " <<getName()<<" come and open the door\n";}
	};

	//一個派生子類,實際觀察者
	class CBaby : public CPerson{
	public:
		CBaby(const std::string& vName) : CPerson(vName) {}
		virtual void act() {std::cout<<"Baby "<<getName()<<" weak up and cry\n";}
	};

	//被觀察者基類
	class CRing
	{
	public:
		CRing() {}
		virtual ~CRing() {}

		void ring()//觸發信號
		{
			__notifyV();
		}

		//增加觀察者
		void add(CPerson* vPerson) {m_Person.push_back(vPerson);}

	private:
		std::vector<CPerson*> m_Person;

		//通知所有觀察者
		virtual void __notifyV()
		{
			std::vector<CPerson*>::iterator It = m_Person.begin();
			while (It != m_Person.end()) (*It++)->act();
		}
	};

	class CGuest : public CRing
	{
	public:
		CGuest() {}
		virtual ~CGuest() {}
	};

	void test()
	{
		CGuest Guest;
		CNurse Nurse("LiSi");
		CBaby  Baby("ZhangSan");

		Guest.add(&Nurse);
		Guest.add(&Baby);
		Guest.ring();//觸發信號
	}
}</span>
爲什麼要用boost::signals呢?原因是上面這個代碼耦合性強,用boost::signals可以來降低耦合性:

<span style="font-size:14px;">#pragma once

#include <algorithm>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/signals2.hpp>

namespace Test_Signal_work
{
	class CGate
	{
		typedef boost::signals2::signal<void(bool, const std::string&)> signal_type;
		typedef signal_type::slot_type slot_type;
	public:
		boost::signals2::connection connect(const slot_type& vSlot)
		{
			return m_EnterOrLiveSig.connect(vSlot);
		}

		void enter(const std::string& vCarId)
		{
			m_EnterOrLiveSig(true, vCarId);
		}

		void leave(const std::string& vCarId)
		{
			m_EnterOrLiveSig(false, vCarId);
		}
	private:
		signal_type m_EnterOrLiveSig;
	};

	class CCarInformation
	{
		typedef boost::signals2::signal<void(const std::string&)> signal_type;
		typedef signal_type::slot_type slot_type;
		typedef std::vector<std::string> cars_type;
	public:
		boost::signals2::connection connect(const slot_type& vSlot) 
		{
			return m_Sig.connect(vSlot);
		}

		void active(bool vEnter, const std::string& vCarId) 
		{
			vEnter ? enter(vCarId) : leave(vCarId);
		}

		//不要這個也行,可以用boost::bind
		void operator()(bool vEnter, const std::string& vCarId) 
		{
			active(vEnter, vCarId);
		}

	private:
		void enter(const std::string& vCarId) 
		{
			cars_type::iterator It = std::find(m_CarsInfo.begin(), m_CarsInfo.end(), vCarId);
			if (It == m_CarsInfo.end()) 
			{
				m_CarsInfo.push_back(vCarId);
				std::cout << "car " << vCarId << " enter!" << std::endl;
			}
			else
			{
				m_Sig(vCarId);
			}
		}

		void leave(const std::string& vCarId) 
		{
			cars_type::iterator It = std::find(m_CarsInfo.begin(), m_CarsInfo.end(), vCarId);
			if (It != m_CarsInfo.end()) 
			{
				std::cout << "car " << vCarId << " leave!" << std::endl;
				m_CarsInfo.erase(It);
			}
			else
			{
				m_Sig(vCarId);
			}
		}

	private:
		signal_type m_Sig;
		cars_type m_CarsInfo;
	};

	class CGuard 
	{
	public:
		CGuard(const std::string& vName) : m_GuardName(vName) {}
		void active(const std::string& vCarId)
		{
			std::cout << m_GuardName << " knew that " << "there is an exception with car " << vCarId << std::endl;
		}

		void operator()(const std::string& vCarId) 
		{
			active(vCarId);
		}
	private:
		std::string m_GuardName;
	};

	void test_fun_1()
	{
		CGuard ZS("ZhangSan");
		CGuard LS("LiSi");

		CCarInformation Info;

		CGate Gate1;
		CGate Gate2;

		Gate1.connect(boost::ref(Info));
		Gate2.connect(boost::ref(Info));

		Info.connect(LS);
		Info.connect(ZS);

		//測試1
		Gate1.enter("CA1001");
		Gate2.enter("CB1002");
		Gate1.leave("CB1002");
		//測試2
		Gate2.leave("CA1003");
		Gate1.enter("CA1004");
		Gate2.enter("CA1004");
		Gate1.leave("CA1004");
	}
}</span>


在看第二個例子:

題目2:模擬簡單的停車場監視器

描述:

車輛進入或離開停車場時,監視器將收到一個通知信息(如唯一標記這輛車的車牌號,進入或離開時間,這裏僅用車牌號),這樣監視器才能跟蹤每兩車的進入和離開,並且監視器能夠在有人進行欺騙行爲時出發警報通知保安。

一個簡單的停車場監視器可以用三個類來實現:CGate,CCarInformation,CGuard。

 

class CGate

{

public:

   void enter(const std::string& vCarId);

   void leave(const std::string& vCarId);

};

CGate必須有enter和leave函數,把車輛的信息發送給CCarInformation。

 

class CCarInformation

{

public:

   void active(bool vEnter, const std::string& vCarId);

private:

   std::vector<std::string> m_CarsInfo;

};

CcarInformation收到CGate的信息時必須有一個active來採取相應的措施,比如某輛車的信息異常側發出警報通知CGuard。

 

class CGuard

{

public:

   void active(const std::string& vCarId);

private:

   std::string m_GuardName;

};

如果CcarInformation發出警報則CGuard必須做出反應。

要求實現功能:

   停車場有兩個門,每個門都可以進出,並且把車輛的出入信息通知給CCarInformation來跟蹤每輛車。同一輛車兩次進入(或兩次離開)時,發出警報通知所有保安。每個門有一個保安。

測試樣例:

  

int main()

{

   //測試1

   Gate1.enter("CA1001");

   Gate2.enter("CB1002");

   Gate1.leave("CB1002");

    //測試2

   Gate2.leave("CA1003");

   Gate1.enter("CA1004");

   Gate2.enter("CA1004");

   Gate1.leave("CA1004");

}

測試1輸出:

   car CA1001 enter!

   car CB1002 enter!

   car CB1002 leave!

測試2輸出:

   ZhanSan knew that there is an exception with car CA1003!

   LiSi knew that there is an exception with car CA1003!

   car CA1004 enter!

   ZhanSan knew that there is an exception with car CA1004!

   LiSi knew that there is an exception with car CA1004!

   car CA1004 leave!

這個例子比前一個例子稍微複雜:

#pragma once

#include <algorithm>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/signals2.hpp>

namespace Test_Signal_work
{
	class CGate
	{
		typedef boost::signals2::signal<void(bool, const std::string&)> signal_type;
		typedef signal_type::slot_type slot_type;
	public:
		boost::signals2::connection connect(const slot_type& vSlot)
		{
			return m_EnterOrLiveSig.connect(vSlot);
		}

		void enter(const std::string& vCarId)
		{
			m_EnterOrLiveSig(true, vCarId);
		}

		void leave(const std::string& vCarId)
		{
			m_EnterOrLiveSig(false, vCarId);
		}
	private:
		signal_type m_EnterOrLiveSig;
	};

	class CCarInformation
	{
		typedef boost::signals2::signal<void(const std::string&)> signal_type;
		typedef signal_type::slot_type slot_type;
		typedef std::vector<std::string> cars_type;
	public:
		boost::signals2::connection connect(const slot_type& vSlot) 
		{
			return m_Sig.connect(vSlot);
		}

		void active(bool vEnter, const std::string& vCarId) 
		{
			vEnter ? enter(vCarId) : leave(vCarId);
		}

		//不要這個也行,可以用boost::bind
		void operator()(bool vEnter, const std::string& vCarId) 
		{
			active(vEnter, vCarId);
		}

	private:
		void enter(const std::string& vCarId) 
		{
			cars_type::iterator It = std::find(m_CarsInfo.begin(), m_CarsInfo.end(), vCarId);
			if (It == m_CarsInfo.end()) 
			{
				m_CarsInfo.push_back(vCarId);
				std::cout << "car " << vCarId << " enter!" << std::endl;
			}
			else
			{
				m_Sig(vCarId);
			}
		}

		void leave(const std::string& vCarId) 
		{
			cars_type::iterator It = std::find(m_CarsInfo.begin(), m_CarsInfo.end(), vCarId);
			if (It != m_CarsInfo.end()) 
			{
				std::cout << "car " << vCarId << " leave!" << std::endl;
				m_CarsInfo.erase(It);
			}
			else
			{
				m_Sig(vCarId);
			}
		}

	private:
		signal_type m_Sig;
		cars_type m_CarsInfo;
	};

	class CGuard 
	{
	public:
		CGuard(const std::string& vName) : m_GuardName(vName) {}
		void active(const std::string& vCarId)
		{
			std::cout << m_GuardName << " knew that " << "there is an exception with car " << vCarId << std::endl;
		}

		void operator()(const std::string& vCarId) 
		{
			active(vCarId);
		}
	private:
		std::string m_GuardName;
	};

	void test_fun_1()
	{
		CGuard ZS("ZhangSan");
		CGuard LS("LiSi");

		CCarInformation Info;

		CGate Gate1;
		CGate Gate2;

		Gate1.connect(boost::ref(Info));
		Gate2.connect(boost::ref(Info));

		Info.connect(LS);
		Info.connect(ZS);

		//測試1
		Gate1.enter("CA1001");
		Gate2.enter("CB1002");
		Gate1.leave("CB1002");
		//測試2
		Gate2.leave("CA1003");
		Gate1.enter("CA1004");
		Gate2.enter("CA1004");
		Gate1.leave("CA1004");
	}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章