假設我有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;
};