组件系统

从基类派生出新的类时,往往会添加新的方法,当该类的对象以基类指针的形式表现出来的时候,我们就无法调用这些的新的方法了。从概念上来看,是因为行为绑定到类型上,父类自然无法调用子类新的行为。在面向对象编程中,行为与类型耦合的比较紧密。

组件系统将对象与行为解耦,所有对象都表现为组件指针,所有行为都表现为接口指针。通过查询接口来获取行为。所有组件都从工厂类产生。

以下是示例代码,代码是从游戏编程精粹里修改而来。

首先我们需要一个类型标识类,因为当对象都表现为组件指针时,只有依赖类型标识类才能区分。

 1 /*------------------------------------------------------------------

 2 // 著作版权:Copyright (C) liuxb

 3 // 创建时间:[liuxb|20131005]

 4 // 功能描述:类型id

 5 //

 6 // 修改时间:

 7 // 修改描述:

 8 // 

 9 //----------------------------------------------------------------*/

10 

11 #pragma once

12 

13 #include <cassert>

14 

15 

16 // 类型id

17 class classid

18 {

19 public:

20     const static unsigned int INVALID_HASH = 0xffffffff; 

21 

22 public:

23     classid(void) { m_hash_value = INVALID_HASH; }

24     explicit classid(unsigned int hash_value) : m_hash_value(hash_value) {}

25     explicit classid(const char* class_name) { m_hash_value = make_hash(class_name); }

26     classid(const classid& rhs) : m_hash_value(rhs.m_hash_value) {}

27     

28     template<typename Type>

29     classid(Type const* type);

30 

31     inline classid& operator = (const classid& rhs);

32     inline classid& operator = (unsigned int hash_value);

33 

34 public:

35     bool is_valid() { return m_hash_value == INVALID_HASH; }

36     operator unsigned int(void) { return m_hash_value; }

37 

38     const bool operator<(const classid& rhs) const { return m_hash_value<rhs.m_hash_value; }

39     const bool operator<=(const classid& rhs) const { return m_hash_value<=rhs.m_hash_value; }

40     const bool operator>(const classid& rhs) const { return m_hash_value>rhs.m_hash_value; }

41     const bool operator>=(const classid& rhs) const { return m_hash_value>=rhs.m_hash_value; }

42     const bool operator==(const classid& rhs) const { return m_hash_value==rhs.m_hash_value; }

43     const bool operator!=(const classid& rhs) const { return m_hash_value!=rhs.m_hash_value; }

44     

45 

46 private:

47     inline unsigned int make_hash(const char* class_name);

48 

49 private:

50     unsigned int m_hash_value;

51 };

52 

53 

54 

55 

56 

57 inline classid& classid::operator = (const classid& rhs) 

58 {

59     if(&rhs != this) m_hash_value = rhs.m_hash_value;

60     return *this;

61 }

62 

63 inline classid& classid::operator = (unsigned int hash_value) 

64 {

65     m_hash_value = hash_value;

66     return *this;

67 }

68 

69 inline unsigned int classid::make_hash(const char* class_name)

70 {

71     const static unsigned int HASH_INIT = 0x811c9dc5;

72     const static unsigned int HASH_PRIME = 0x01000193;

73 

74     assert(class_name!=0 && class_name[0]!=0);

75     const unsigned char* pname = (const unsigned char*)class_name;

76     unsigned int hash = HASH_INIT;

77 

78     while (*pname)

79     {

80         hash *= HASH_PRIME;

81         hash ^= (unsigned int)(*pname);

82         ++pname;

83     }

84     return hash;

85 }

86 

87 template<typename Type>

88 inline classid::classid(Type const* type)

89 {

90     m_hash_value = make_hash(typeid(Type).name());

91 }
View Code

接下来需要一个接口标识类,用于保存组件里的接口指针。本来类型标识类也足以完成这个功能,但是游戏编程精粹里给接口添加了一个版本号的功能。而我这为了简单就没有使用该类。

 1 /*------------------------------------------------------------------

 2 // 著作版权:Copyright (C) liuxb

 3 // 创建时间:[liuxb|20131006]

 4 // 功能描述:接口标识id

 5 //

 6 // 修改时间:

 7 // 修改描述:

 8 // 

 9 //----------------------------------------------------------------*/

10 

11 #pragma once

12 

13 #include "class_version.hpp"

14 #include "classid.hpp"

15 

16 struct interfaceid

17 {

18 public:

19     classid classid;

20     int version;

21 

22 public:

23     template<class Type>

24     explicit interfaceid(const Type* type)

25         : version(version_number(type))

26         , classid(type)

27     {

28 

29     }

30 

31 public:

32     int version_number(...) { return 0; }

33 

34     template<int number>

35     int version_number(const class_version<number>*)

36     {

37         return number;

38     }

39 

40     bool operator==(const interfaceid& iid)

41     {

42         return    (version == -iid.version || version == iid.version) && classid == iid.classid;

43     }

44 

45 

46     bool operator<(const interfaceid& iid) const

47     {

48         if(classid == iid.classid) return version < iid.version;

49         return classid < iid.classid;

50     }

51 };

52 

53 

54 

55 struct interfaceid_withno_version

56 {

57     classid classid;

58 

59 

60     template<class Type>

61     explicit interfaceid_withno_version(const Type* type)

62         :    classid(type)

63     {}

64 

65 

66     bool operator==(const interfaceid_withno_version& iid)

67     {

68         return    classid == iid.classid;

69     }

70 

71     bool operator<(const interfaceid_withno_version& iid) const

72     {

73         return classid < iid.classid;

74     }

75 };
View Code

有了classid,interfaceid类之后就可以写组件基类了。handle_message方法使得对象可以接收以及处理感兴趣的事件。

 1 /*------------------------------------------------------------------

 2 // 著作版权:Copyright (C) liuxb

 3 // 创建时间:[liuxb|20131005]

 4 // 功能描述:组件接口

 5 //

 6 // 修改时间:

 7 // 修改描述:

 8 // 

 9 //----------------------------------------------------------------*/

10 

11 #pragma once

12 

13 #include <map>

14 #include "classid.hpp"

15 #include "interfaceid.hpp"

16 

17 

18 // 消息处理函数的返回类型

19 enum emessage_result

20 {

21     mr_false,

22     mr_true,

23     mr_ignored,

24     mr_error

25 };

26 

27 

28 // 前置声明

29 class ientity;

30 class message;

31 

32 

33 

34 // 组件接口

35 class icompoenent

36 {

37     typedef interfaceid_withno_version                    interfaceid;

38     typedef std::map<interfaceid, void*>                interface_map;

39 public:

40     virtual ~icompoenent(void) {};

41 

42 public:

43     virtual emessage_result        handle_message(const ientity* entity, const message& msg) { return mr_ignored; }

44     classid            get_classid(void) const { return m_classid; }

45 

46     // 添加需要导出的接口指针,用于对象构造时确定需导出的接口指针

47     // 

48     template<class Type>

49     void            expose_interface(Type* type);

50     // 查询接口指针

51     template<class Type>

52     Type*            query_interface();

53     

54 private:

55     void            set_classid(const classid& oid) { m_classid = oid; }

56     void*            query_interface(const interfaceid& id);

57 private:

58     classid            m_classid;

59     interface_map    m_interface_map;

60 };

61 

62 

63 

64 template<class Type>

65 inline void icompoenent::expose_interface(Type* type)

66 {

67     m_interface_map[interfaceid(type)] = type;

68 }

69 

70 template<class Type>

71 inline Type* icompoenent::query_interface()

72 {

73     Type* type = 0;

74     return reinterpret_cast<Type*>(query_interface(interfaceid(type)));

75 }

76 

77 inline void* icompoenent::query_interface(const interfaceid& id)

78 {

79     interface_map::iterator it = m_interface_map.find(id);

80     if(it!=m_interface_map.end()) return it->second;

81     return 0;

82 }
View Code

最后一个是工厂类,如果写的更精细一点,应该将create函数模板化,以接受带参数的对象构造函数。这里没有提供,各位可以自行添加。

  1 /*------------------------------------------------------------------

  2 // 著作版权:Copyright (C) liuxb

  3 // 创建时间:[liuxb|20131005]

  4 // 功能描述:工厂

  5 //

  6 // 修改时间:

  7 // 修改描述:

  8 // 

  9 //----------------------------------------------------------------*/

 10 

 11 #pragma once

 12 

 13 #include <cassert>

 14 #include <list>

 15 #include <map>

 16 

 17 #include "classid.hpp"

 18 #include "icompoenent.hpp"

 19 

 20 // 工厂类

 21 class factory

 22 {

 23 public:

 24     virtual        ~factory(void) ;

 25 

 26 public:

 27     static        factory& singleton();

 28 

 29 public:

 30     template<class Type> 

 31     icompoenent*    create(void);

 32 

 33 public:

 34     template<class Type> 

 35     void            remove_support(void);

 36 

 37     template<class Type> 

 38     void            support(void);    

 39 

 40     template<class Type>

 41     bool            is_supported();

 42 

 43     classid            supported_typeid(unsigned int index);

 44     unsigned int    number_of_supported_types();

 45 

 46 private:

 47     struct base_constructor

 48     {

 49         virtual icompoenent* construct() = 0;

 50     };

 51 

 52     template<class Type>

 53     struct constructor : base_constructor

 54     {

 55         icompoenent* construct()

 56         {

 57             return new Type();

 58         }

 59     };

 60 

 61     typedef std::map<classid, base_constructor*> constructor_map;

 62 

 63 private:

 64     base_constructor* find_constructor(const classid& id);

 65 

 66     icompoenent*    create(const classid& id);

 67     bool            is_supported(const classid& id);

 68     void            remove_support(const classid& id);

 69 

 70 private:

 71     constructor_map        m_constructor_map;

 72 };

 73 

 74 

 75 

 76 inline factory::~factory()

 77 {

 78     typedef constructor_map::iterator iterator;

 79     for(iterator it = m_constructor_map.begin(); it!=m_constructor_map.end(); ++it)

 80     {

 81         delete it->second;

 82     }

 83 }

 84 

 85 

 86 inline factory& factory::singleton()

 87 {

 88     static factory    fac;

 89     return fac;

 90 }

 91 

 92 

 93 

 94 

 95 inline icompoenent* factory::create(const classid& id)

 96 {

 97     base_constructor* constructor = find_constructor(id);

 98     if(constructor) return constructor->construct();

 99     return 0;

100 }

101 

102 

103 template<class Type>

104 inline icompoenent* factory::create(void)

105 {

106     Type* type = 0;

107     return create(classid(type));

108 }

109 

110 

111 

112 inline void factory::remove_support(const classid& id)

113 {

114     constructor_map::iterator it = m_constructor_map.find(id);

115     if(it!=m_constructor_map.end())

116     {

117         delete it->second;

118         m_constructor_map.erase(it);

119     }

120 }

121 

122 

123 template<class Type>

124 inline void factory::remove_support()

125 {

126     Type* type = 0;

127     remove_support(classid(type));

128 }

129 

130 

131 template<class Type>

132 inline void factory::support()

133 {

134     Type* type = 0;

135     m_constructor_map[classid(type)] = new constructor<Type>();

136 }

137 

138 

139 inline classid factory::supported_typeid(unsigned int index)

140 {

141     constructor_map::iterator it = m_constructor_map.begin();

142     assert(index < m_constructor_map.size());

143 

144     while(index--) 

145     {

146         ++it;

147     }

148     return it->first;

149 }

150 

151 

152 

153 inline unsigned int factory::number_of_supported_types()

154 {

155     return m_constructor_map.size();

156 }

157 

158 

159 inline bool factory::is_supported(const classid& id)

160 {

161     return find_constructor(id)!=0;

162 }

163 

164 

165 template<class Type>

166 inline bool factory::is_supported()

167 {

168     Type* type = 0;

169     return is_supported(classid(type))!=0;

170 }

171 

172 

173 inline factory::base_constructor* factory::find_constructor(const classid& id)

174 {

175     constructor_map::iterator it = m_constructor_map.find(id);

176     if(it!=m_constructor_map.end()) return it->second;

177     return 0;

178 }

179 

180 // 让生活变得更美好

181 #define Factory                factory::singleton()
View Code

至此一个简单的组件系统就有了。接下来是测试代码。

 1 // component_system.cpp : 定义控制台应用程序的入口点。

 2 //

 3 

 4 #include "stdafx.h"

 5 

 6 #include "factory.hpp"

 7 #include "interfaceid.hpp"

 8 #include "classid.hpp"

 9 #include "icompoenent.hpp"

10 

11 #include <string>

12 

13 

14 struct iname

15 {

16     virtual const char* name() = 0;

17 };

18 

19 struct ipos

20 {

21     virtual int length() = 0;

22 };

23 

24 struct position : public ipos

25 {

26     int x;

27     int y;

28 

29     virtual int length() { return x*x + y*y; }

30 };

31 

32 

33 class compoenent : public icompoenent, public iname

34 {

35 public:

36     compoenent()

37     {

38         expose_interface<ipos>(&m_pos);

39         expose_interface<iname>(this);

40         m_name = "liuxb";

41         m_pos.x = 3;

42         m_pos.y = 4;

43     }

44 public:

45     const char* name() { return m_name.c_str(); }

46 

47 private:

48     std::string        m_name;

49     position        m_pos;

50 };

51 

52 

53 int _tmain(int argc, _TCHAR* argv[])

54 {

55     Factory.support<compoenent>();

56 

57     icompoenent* pcmp = factory::singleton().create<compoenent>();

58 

59     iname* name = pcmp->query_interface<iname>();

60     ipos* ppos = pcmp->query_interface<ipos>();

61 

62 

63     printf("cmp name = %s\n", name->name());

64     printf("cmp length = %d\n", ppos->length());

65 

66     return 0;

67 }
View Code

 

 

 

 

你可能感兴趣的:(系统)