C++ template component architecture
A set of C++ templates for implementing a component architecture. This architecture allows developers to create easily extensible applications from components. A core engine defines a set of interfaces that components can implement to extend behaviour.
Several projects implement a similar architecture, including Eclipse and Trac.
Core -> Interface -> Component Implementation
Here is a completely contrived example, followed by the full template system below:
#include <iostream> #include "ComponentArchitecture.h" struct MyInterface : public Interface<MyInterface> { virtual void my_interface_method(int some_argument) = 0; }; struct MyOtherInterface : public Interface<MyOtherInterface> { virtual void my_other_interface_method(int some_other_argument) = 0; }; /* Class implementing the MyInterface and MyOtherInterface interfaces */ struct MyComponent : MyInterface, MyOtherInterface { void my_interface_method(int some_argument) { std::cout << "my_interface_method(" << some_argument << ")" << std::endl; } void my_other_interface_method(int some_other_argument) { std::cout << "my_other_interface_method(" << some_other_argument << ")" << std::endl; } }; REGISTER_EXTENSION(MyComponent) int main(int argc, char **argv) { /* Call my_interface_method() on all implementations of MyInterface */ for (MyInterface::iterator i = MyInterface::begin(); i != MyInterface::end(); ++i) (*i)->my_interface_method(10); /* Call my_other_interface_method() on all implementations of MyOtherInterface */ for (MyOtherInterface::iterator i = MyOtherInterface::begin(); i != MyOtherInterface::end(); ++i) (*i)->my_other_interface_method(10); return 0; }
And here is the actual C++ implementation of the component architecture.
#ifndef COMPONENT_PATTERN_H__ #define COMPONENT_PATTERN_H__ #include <list> /** Singleton template to ease construction of singleton classes. Use thus: class Foo : public Singleton<Foo> { private : friend class Singleton<Foo>; // Subclass constructor must be private to enforce singleton // semantics. Foo(); }; */ template <typename T> class Singleton { public : /// Access the singleton object. static T &singleton() { if (!msingleton) msingleton = new T(); return *msingleton; } /** Call on program termination. If shutdown() is not called, the singleton destructor will not be called. */ static int shutdown(int rv = 0) { delete msingleton; msingleton = 0; return rv; } protected : Singleton() {} private : Singleton(const Singleton &); static T *msingleton; }; template <typename T> T *Singleton<T>::msingleton; /* Singleton class for accessing all of the implementations of a given Interface. It is easier to use the Interface<> iterator methods, but you can use these directly. */ template <typename T> class ExtensionPoint : public Singleton<ExtensionPoint<T> > { public : typedef std::list<T*> Extensions; typedef typename Extensions::iterator iterator; typedef typename Extensions::const_iterator const_iterator; static void register_interface(T *interface) { Singleton<ExtensionPoint<T> >::singleton().mextensioninstances.push_back(interface); } static iterator begin() { return Singleton<ExtensionPoint<T> >::singleton().mextensioninstances.begin(); } static iterator end() { return Singleton<ExtensionPoint<T> >::singleton().mextensioninstances.end(); } private : friend class Singleton<ExtensionPoint>; ExtensionPoint() {} Extensions mextensioninstances; }; /** Define a new interface. All interface methods should be pure virtual to force implementation in the extensions. eg. struct IHelpProvider : Interface<IHelpProvider> { virtual std::string get_help(std::string term) = 0; }; To subsequently iterate over all objects implementing the IHelpProvider interface: for (IHelpProvider::iterator i = IHelpProvider::begin(); i != IHelpProvider::end(); ++i) cout << (*i)->get_help(term) << endl; */ template <typename T> class Interface : public Singleton<T> { public : typedef std::list<T*> Extensions; typedef typename Extensions::iterator iterator; typedef typename Extensions::const_iterator const_iterator; static iterator begin() { return ExtensionPoint<T>::begin(); } static iterator end() { return ExtensionPoint<T>::end(); } protected : virtual ~Interface() {} Interface() { ExtensionPoint<T>::register_interface(static_cast<T*>(this)); } }; template <typename T> struct RegisterExtension { RegisterExtension() { Singleton<T>::singleton(); } }; /** Helper macro to instantiate an extension object. Probably not necessary, but makes it easier to find extensions in source. eg. Without singleton protection, simply: struct ManHelp : IHelpProvider { std::string get_help(std::string term) { if (term.substr(0, 4) == "man:") .... } }; Or as a singleton: struct ManHelp : Singleton<ManHelp>, IHelpProvider { std::string get_help(std::string term) { if (term.substr(0, 4) == "man:") .... } // Prevent accidental instantation private : friend class Singleton<ManHelp>; ManHelp() {} }; Then finally: REGISTER_EXTENSION(ManHelp) */ #define REGISTER_EXTENSION(extension) \ static RegisterExtension<extension> __##extension##_extension__; #endif
