EOS插件继承机制讲解
1、EOS的插件接口
class abstract_plugin {
public:
enum state {
registered, ///< the plugin is constructed but doesn't do anything
initialized, ///< the plugin has initialized any state required but is idle
started, ///< the plugin is actively running
stopped ///< the plugin is no longer running
};
virtual ~abstract_plugin(){}
virtual state get_state()const = 0;
virtual const std::string& name()const = 0;
virtual void set_program_options( options_description& cli, options_description& cfg ) = 0;
virtual void initialize(const variables_map& options) = 0;
virtual void startup() = 0;
virtual void shutdown() = 0;
};
从插件的基类中可以看出插件有4个状态已注册、已初始化、运行、停止。其中
已注册(registered): 表示插件对象已经被实例化,但没有做任何事情。
已初始化(initialized): 表示插件的参数已经被初始化,可以随时运行
运行(started): 表示插件已经在运行状态
停止(stopped): 表示插件已经停止运行
插件的接口提供了所有插件对外提供的基本操作。
get_state:获取插件当前的状态
name:获取插件名称
set_program_options:设置插件所需要的参数
initialize:插件初始化
startup:插件运行
shutdown:插件停止
2、插件模板
EOS插件实现所用技术比较复杂,代码也比较晦涩。首先EOS插件有三个层次,第一层是接口abstract_plugin,为插件提供统一的访问接口;第二层是模板层plugin,根据插件类型去推演出插件自己的父类;第三层EOS插件根据自己的业务去实现具体的方法。

EOS插件使用了C++的多态机制,父类只提供接口,不同的子类根据自己业务实现自己方法。其次EOS插件使用模板机制,根据不同的插件类去推演出自己的父类,EOS插件采用代理的设计模式完成实现业务方法与接口方法不同。
template<typename Impl>
class plugin : public abstract_plugin {
public:
plugin():_name(boost::core::demangle(typeid(Impl).name())){}
virtual ~plugin(){}
virtual state get_state()const override { return _state; }
virtual const std::string& name()const override { return _name; }
virtual void register_dependencies() {
static_cast<Impl*>(this)->plugin_requires([&](auto& plug){});
}
virtual void initialize(const variables_map& options) override {
if(_state == registered) {
_state = initialized;
static_cast<Impl*>(this)->plugin_requires([&](auto& plug){ plug.initialize(options); });
static_cast<Impl*>(this)->plugin_initialize(options);
//ilog( "initializing plugin ${name}", ("name",name()) );
app().plugin_initialized(*this);
}
assert(_state == initialized); /// if initial state was not registered, final state cannot be initiaized
}
virtual void startup() override {
if(_state == initialized) {
_state = started;
static_cast<Impl*>(this)->plugin_requires([&](auto& plug){ plug.startup(); });
static_cast<Impl*>(this)->plugin_startup();
app().plugin_started(*this);
}
assert(_state == started); // if initial state was not initialized, final state cannot be started
}
virtual void shutdown() override {
if(_state == started) {
_state = stopped;
//ilog( "shutting down plugin ${name}", ("name",name()) );
static_cast<Impl*>(this)->plugin_shutdown();
}
}
protected:
plugin(const string& name) : _name(name){}
private:
state _state = abstract_plugin::registered;
std::string _name;
};
EOS插件中比较难理解的是插件模板机制,插件用自己的类型传入模板中去推演自己的父类,导致无法理解(自己怎么能够继承自己呢)。不理解的原因在于不明白模板的运行是在编译器,只要提供与模板接口一样就可以,第二、类的声明和类的定义在编译器的操作是不一样的。类的声明后就可以创建指针,任何类型的指针都可以编译器得到其所占空间的大小。而类的定义就需要确定类的实现具休是什么样子,编译器才能在编译期确定类对象的大小,才不使编译器报错。
3、举个例子-chain_plugin模板实现
class plugin : public abstract_plugin {
public:
plugin() :_name(boost::core::demangle(typeid(chain_plugin).name())) {}
virtual ~plugin() {}
virtual state get_state()const override { return _state; }
virtual const std::string& name()const override { return _name; }
virtual void register_dependencies() {
static_cast<chain_plugin*>(this)->plugin_requires([&](auto& plug) {});
}
virtual void initialize(const variables_map& options) override {
if (_state == registered) {
_state = initialized;
static_cast<chain_plugin*>(this)->plugin_requires([&](auto& plug) { plug.initialize(options); });
static_cast<chain_plugin*>(this)->plugin_initialize(options);
//ilog( "initializing plugin ${name}", ("name",name()) );
app().plugin_initialized(*this);
}
assert(_state == initialized); /// if initial state was not registered, final state cannot be initiaized
}
virtual void startup() override {
if (_state == initialized) {
_state = started;
static_cast<chain_plugin*>(this)->plugin_requires([&](auto& plug) { plug.startup(); });
static_cast<chain_plugin*>(this)->plugin_startup();
app().plugin_started(*this);
}
assert(_state == started); // if initial state was not initialized, final state cannot be started
}
virtual void shutdown() override {
if (_state == started) {
_state = stopped;
//ilog( "shutting down plugin ${name}", ("name",name()) );
static_cast<chain_plugin*>(this)->plugin_shutdown();
}
}
protected:
plugin(const string& name) : _name(name) {}
private:
state _state = abstract_plugin::registered;
std::string _name;
};
网友评论