C++屬性註冊機制

需求是這樣:
假設我有Class Base是一個對任何使用者都可見的接口基類,現在某個對外完全封閉的模塊有Class A : public Base,Class B : public Base等A、B、C.....等一系列對Base類的拓展和實現。使用者只能獲得 Base* 指針類型,卻不知道是A、B、C還是D哪個子類的具體實現。
我們需要讓使用者通過Base*指針同樣能操作(get、set)A、B、C的屬性...........在實際編程中,這種設計其實很有用,我可以無限讓用戶拓展他自己組織的子類,而只要通過Base指針進行操作,對外部封閉了具體類型。
那麼這個怎麼實現呢?這裏介紹前段時間學習得來的屬性機制
屬性,顧名思義,很容易聯想到成員變量。那麼要做到以上需求主要基類提供一個註冊屬性的機制就夠了,不管子類有和屬性,都可以通過基類繼續註冊,然後對外暴露

下面是屬性基類的定義:

class PropertyBase
		{
		protected:
	
			PropertyBase(const Ogre::String& name, const Ogre::String& description, PropertyType type)
				: mName(name),mDescription(description),mType(type)	
			{}

			PropertyBase(const PropertyBase& pro){}

			void operator= (const PropertyBase& pro){}

		public:
			virtual ~PropertyBase(){}
			
			const Ogre::String& getName() const { return mName; }

			const Ogre::String& getDescription() const { return mDescription; }

			PropertyType getType() const { return mType; }
			
			static PropertyType getTypeForValue(const short& val) { return PROP_SHORT; }
			static PropertyType getTypeForValue(const unsigned short& val) { return PROP_UNSIGNED_SHORT; }
			static PropertyType getTypeForValue(const int& val) { return PROP_INT; }
			.....
			....

		protected:
			Ogre::String mName;
			Ogre::String mDescription;
			PropertyType mType;
		};
下面是屬性的定義:
template <typename T>
		class Property : public PropertyBase
		{
		public:
			typedef PropertyGetterFunction<T> getter_func;
			typedef PropertySetterFunction<T> setter_func;

			Property(const Ogre::String& name, const Ogre::String& description, PropertyType type,
					 getter_func getter, setter_func setter = setter_func())
				: PropertyBase(name,description,type),mGetter(getter),mSetter(setter){}
			virtual ~Property(void){}

			virtual void set(const T& val)
			{
				if(!mSetter.isNull())
					mSetter(val);
			}

			virtual T get() const
			{
				return mGetter();
			}

			Ogre::Any getValue() const
			{
				return Ogre::Any(get());
			}

		protected:
			getter_func mGetter;
			setter_func mSetter;
		};


針對自定義類型(如結構體),我們也可以拆分爲簡單系統內置類型,所以添加一個屬性集繼承屬性基類:

class PropertySet : public PropertyBase
		{
		public:
			typedef Ogre::map<Ogre::String, PropertyBase*>::type PropertyMap;
			typedef PropertyMap::value_type PropertyMapValue;
			typedef PropertyMap::iterator PropertyMapIter;

			PropertySet(const Ogre::String& name, const Ogre::String& description)
				: PropertyBase(name,description,PROP_SET)
			{}

			virtual ~PropertySet()
			{
				....
			}

			void addProperty(PropertyBase* prop)
			{
				mPropertyMap.insert(PropertyMapValue(prop->getName(),prop));
			}

			PropertyBase* getProperty(const Ogre::String& name) const
			{
				if(mPropertyMap.find(name) == mPropertyMap.end())
					return NULL;
				return mPropertyMap.find(name)->second;
			}

			bool hasProperty(const Ogre::String& name) const
			{
				if(mPropertyMap.find(name) == mPropertyMap.end())
					return false;
				return true;
			}

			bool setAutoValue(const Ogre::String& name, const Ogre::String& value);

			template<typename T>
			void getValue(const Ogre::String& name, T& refVal) const
			{
				getPropertyImpl<T>(name,refVal,getTypeForValue(refVal));
			}

			template<typename T>
			void setValue(const Ogre::String& name, T& val)
			{
				setPropertyImpl<T>(name,val,getTypeForValue(val));
			}

			PropertyMap getPropertyMap()
			{
				return mPropertyMap;
			}

			static bool matchPropertyStringSet(PropertySet& proSet, PropertyStringSet& proStrSet);


		protected:
			PropertyMap mPropertyMap;
			template <typename T>
			void setPropertyImpl(const Ogre::String& name, const T& val, PropertyType typeCheck)
			{
				PropertyBase* baseProp = getProperty(name);
				if(baseProp->getType() == PROP_SET)
				{
					。。。
				}
				else if (baseProp->getType() != typeCheck)
				{
					。。。
				}
				static_cast<Property<T>*>(baseProp)->set(val);
			}

			template <typename T>
			void getPropertyImpl(const Ogre::String& name, T& refVal, PropertyType typeCheck) const
			{
				PropertyBase* baseProp = getProperty(name);
				if(baseProp->getType() == PROP_SET)
				{
					。。。
				}
				else if (baseProp->getType() != typeCheck)
				{
					。。。
				}

				refVal = static_cast<Property<T>*>(baseProp)->get(val);
			}
		};
	}
}


現在爲止,屬性的定義就好了,符合屬性用屬性集表示。其實我們可以發現,我們需要註冊的子類其實也就是一個屬性集所以只要Class Base : PropertySet 那麼這樣就能滿足需求。當然直接定義一個PropertySet作爲成員變量也能滿足需求這裏介紹一下PropertyGetterFunction<T>和PropertySetterFunction<T>這兩個類其實很類似與boost::Function,也就是對成員函數的封裝當然我還可以定義一個一下的類,有註釋就不詳細說明了:

/**
		*定義所有繼承屬性基類的對外接口
		*/
		class RENDERLIB_EXPORT PropertyClassBase
		{
		public:
			/*
			*@fuction 構造
			*@param	rootName 屬性集根名字
			*@param	description 屬性集的描述
			*@time 2013/10/16 13:49:17
			*/
			PropertyClassBase(const Ogre::String& rootName, const Ogre::String& description)
			{
				mPropertySet = new PropertySet(rootName,description);
			}

			/*
			*@fuction 析構
			*@time 2013/10/16 13:50:10
			*/
			virtual ~PropertyClassBase(void)
			{
				delete mPropertySet;
				mPropertySet = NULL;
			}

			/*
			*@fuction 獲取指定名字的子屬性集合	
			*@time 2013/10/16 13:27:59
			*/
			inline PropertySet* getChildPropertySet(const Ogre::String& name)
			{
				PropertyBase* base = mPropertySet->getProperty(name);
				if( base->getType() == PROP_SET)
					return dynamic_cast<PropertySet*>(base);
				return NULL;
			}

			/*
			*@fuction 獲取屬性	
			*@time 2013/10/14 10:11:15
			*/
			template <typename T>
			inline Property<T>* getProperty(const Ogre::String& name)
			{
				PropertyBase* base = mPropertySet->getProperty(name);
				if( base->getType() != PROP_SET)
					return dynamic_cast<Property<T>*>(base);
			}

			/*
			*@fuction 查詢屬性是否存在	
			*@time 2013/10/14 10:11:31
			*/
			inline bool hasProperty(const Ogre::String& name) const
			{
				return mPropertySet->hasProperty(name);
			}

			/*
			*@fuction 智能匹配設置屬性
			*@time 2013/10/15 17:11:11
			*/
			inline bool setAutoValue(const Ogre::String& name, const Ogre::String& value)
			{
				return mPropertySet->setAutoValue(name,value);
			}

			/*
			*@fuction 獲取屬性值	
			*@time 2013/10/14 10:21:55
			*/
			template<typename T>
			inline void getValue(const Ogre::String& name, T& refVal) const
			{
				mPropertySet->getValue<T>(name,refVal);
			}

			/*
			*@fuction 設置屬性值	
			*@time 2013/10/14 10:24:36
			*/
			template<typename T>
			inline void setValue(const Ogre::String& name, T& val)
			{
				mPropertySet->setValue<T>(name,val);
			}

			/*
			*@fuction 自動匹配PropertyStringSet裏面的字符串值
			*@time 2013/10/16 14:13:03
			*/
			inline bool matchPropertyStringSet(PropertyStringSet& proStrSet)
			{
				return PropertySet::matchPropertyStringSet(*mPropertySet,proStrSet);
			}

			/*
			*@fuction 獲取屬性集合映射	
			*@time 2013/10/14 10:30:27
			*/
			inline PropertySet::PropertyMap getPropertyMap() 
			{
				return mPropertySet->getPropertyMap();
			}

		protected:

			//屬性集合
			PropertySet* mPropertySet;
		};



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