एक टिप्पणी:
आर्टेमिस कार्यान्वयन दिलचस्प है। मैं एक समान समाधान के साथ आया, इसके अलावा मैंने अपने घटकों को "गुण" और "व्यवहार" कहा। विभिन्न प्रकार के घटकों के इस दृष्टिकोण ने मेरे लिए बहुत अच्छी तरह से काम किया है।
समाधान के बारे में:
कोड का उपयोग करना आसान है, लेकिन यदि आप 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);
}
कार्यान्वयन
कार्यान्वयन उतना बुरा नहीं है, लेकिन यह अभी भी बहुत जटिल है; इसके लिए टेम्प्लेट और फंक्शन पॉइंटर्स के कुछ ज्ञान की आवश्यकता होती है।
नोट: जोएस्सेनिग ने टिप्पणियों में कुछ अच्छे अंक बनाए हैं, मुख्य रूप से इस बात पर कि मेरे पिछले क्रियान्वयन ने कोड के अनुकूलन में कितना अच्छा संकलन किया है, इस बारे में कई धारणाएं हैं; मुद्दा हानिकारक नहीं था, इमो, लेकिन इसने मुझे भी बग कर दिया। मैंने यह भी देखा कि पूर्व COMPONENT_REGISTER
मैक्रो टेम्पलेट्स के साथ काम नहीं करता था।
मैंने कोड बदल दिया है और अब उन सभी समस्याओं को ठीक किया जाना चाहिए। मैक्रो टेम्प्लेट के साथ काम करता है और जिन मुद्दों को जो उठाया गया है, उन्हें संबोधित किया गया है: अब कंपाइलरों के लिए अनावश्यक कोड को अनुकूलित करना बहुत आसान है।
घटक / 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;
}
लुआ के साथ विस्तार
मुझे ध्यान देना चाहिए कि थोड़ा सा काम के साथ (यह बहुत कठिन नहीं है), इसका उपयोग सी ++ या लुआ में परिभाषित घटकों के साथ मूल रूप से काम करने के लिए किया जा सकता है, इसके बारे में कभी भी विचार किए बिना।