ความคิดเห็น:
การนำอาร์ทิมิสมาใช้เป็นสิ่งที่น่าสนใจ ฉันคิดวิธีแก้ปัญหาที่คล้ายกันยกเว้นฉันเรียกองค์ประกอบของฉันว่า "แอตทริบิวต์" และ "พฤติกรรม" วิธีการแยกประเภทของส่วนประกอบนี้ทำงานได้ดีมากสำหรับฉัน
เกี่ยวกับการแก้ปัญหา:
รหัสนั้นใช้งานง่าย แต่การใช้งานอาจยากที่จะติดตามหากคุณไม่เคยใช้ C ++ มาก่อน ดังนั้น...
อินเทอร์เฟซที่ต้องการ
สิ่งที่ฉันทำคือการมีที่เก็บส่วนกลางของส่วนประกอบทั้งหมด คอมโพเนนต์แต่ละชนิดถูกแม็พกับสตริงที่แน่นอน (ซึ่งแทนชื่อคอมโพเนนต์) นี่คือวิธีที่คุณใช้ระบบ:
// Every time you write a new component class you have to register it.
// For that you use the `COMPONENT_REGISTER` macro.
class RenderingComponent : public Component
{
// Bla, bla
};
COMPONENT_REGISTER(RenderingComponent, "RenderingComponent")
int main()
{
// To then create an instance of a registered component all you have
// to do is call the `create` function like so...
Component* comp = component::create("RenderingComponent");
// I found that if you have a special `create` function that returns a
// pointer, it's best to have a corresponding `destroy` function
// instead of using `delete` directly.
component::destroy(comp);
}
การดำเนินการ
การติดตั้งใช้งานไม่ได้แย่ขนาดนั้น แต่มันก็ยังค่อนข้างซับซ้อน มันต้องมีความรู้เกี่ยวกับเทมเพลตและพอยน์เตอร์ฟังก์ชั่น
หมายเหตุ: Joe Wreschnig ได้ให้คะแนนที่ดีในความคิดเห็นส่วนใหญ่เกี่ยวกับวิธีการใช้งานก่อนหน้าของฉันทำข้อสันนิษฐานมากเกินไปเกี่ยวกับวิธีการที่ดีที่คอมไพเลอร์เป็นรหัสการเพิ่มประสิทธิภาพ; ปัญหาไม่เป็นอันตราย imo แต่มันก็ทำให้ฉันด้วย ฉันยังสังเกตเห็นว่าCOMPONENT_REGISTER
มาโครก่อนหน้าไม่ทำงานกับเทมเพลต
ฉันได้เปลี่ยนรหัสและตอนนี้ปัญหาเหล่านั้นควรได้รับการแก้ไขแล้ว มาโครทำงานกับเทมเพลตและปัญหาที่ Joe ฟื้นคืนมาได้รับการแก้ไขแล้วตอนนี้การคอมไพเลอร์เพื่อเพิ่มประสิทธิภาพโค้ดที่ไม่จำเป็นออกไป
องค์ประกอบ / component.h
#ifndef COMPONENT_COMPONENT_H
#define COMPONENT_COMPONENT_H
// Standard libraries
#include <string>
// Custom libraries
#include "detail.h"
class Component
{
// ...
};
namespace component
{
Component* create(const std::string& name);
void destroy(const Component* comp);
}
#define COMPONENT_REGISTER(TYPE, NAME) \
namespace component { \
namespace detail { \
namespace \
{ \
template<class T> \
class ComponentRegistration; \
\
template<> \
class ComponentRegistration<TYPE> \
{ \
static const ::component::detail::RegistryEntry<TYPE>& reg; \
}; \
\
const ::component::detail::RegistryEntry<TYPE>& \
ComponentRegistration<TYPE>::reg = \
::component::detail::RegistryEntry<TYPE>::Instance(NAME); \
}}}
#endif // COMPONENT_COMPONENT_H
องค์ประกอบ / detail.h
#ifndef COMPONENT_DETAIL_H
#define COMPONENT_DETAIL_H
// Standard libraries
#include <map>
#include <string>
#include <utility>
class Component;
namespace component
{
namespace detail
{
typedef Component* (*CreateComponentFunc)();
typedef std::map<std::string, CreateComponentFunc> ComponentRegistry;
inline ComponentRegistry& getComponentRegistry()
{
static ComponentRegistry reg;
return reg;
}
template<class T>
Component* createComponent() {
return new T;
}
template<class T>
struct RegistryEntry
{
public:
static RegistryEntry<T>& Instance(const std::string& name)
{
// Because I use a singleton here, even though `COMPONENT_REGISTER`
// is expanded in multiple translation units, the constructor
// will only be executed once. Only this cheap `Instance` function
// (which most likely gets inlined) is executed multiple times.
static RegistryEntry<T> inst(name);
return inst;
}
private:
RegistryEntry(const std::string& name)
{
ComponentRegistry& reg = getComponentRegistry();
CreateComponentFunc func = createComponent<T>;
std::pair<ComponentRegistry::iterator, bool> ret =
reg.insert(ComponentRegistry::value_type(name, func));
if (ret.second == false) {
// This means there already is a component registered to
// this name. You should handle this error as you see fit.
}
}
RegistryEntry(const RegistryEntry<T>&) = delete; // C++11 feature
RegistryEntry& operator=(const RegistryEntry<T>&) = delete;
};
} // namespace detail
} // namespace component
#endif // COMPONENT_DETAIL_H
องค์ประกอบ / component.cpp
// Matching header
#include "component.h"
// Standard libraries
#include <string>
// Custom libraries
#include "detail.h"
Component* component::create(const std::string& name)
{
detail::ComponentRegistry& reg = detail::getComponentRegistry();
detail::ComponentRegistry::iterator it = reg.find(name);
if (it == reg.end()) {
// This happens when there is no component registered to this
// name. Here I return a null pointer, but you can handle this
// error differently if it suits you better.
return nullptr;
}
detail::CreateComponentFunc func = it->second;
return func();
}
void component::destroy(const Component* comp)
{
delete comp;
}
ขยายด้วย Lua
ฉันควรทราบว่าด้วยการทำงานเล็กน้อย (มันไม่ยากมาก) สิ่งนี้สามารถใช้เพื่อทำงานกับส่วนประกอบที่กำหนดใน C ++ หรือ Lua อย่างราบรื่นโดยไม่ต้องคิดอะไรเลย