EOS插件繼承機(jī)制講解
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個(gè)狀態(tài)已注冊(cè)币呵、已初始化、運(yùn)行侨颈、停止余赢。其中
已注冊(cè)(registered): 表示插件對(duì)象已經(jīng)被實(shí)例化,但沒(méi)有做任何事情哈垢。
已初始化(initialized): 表示插件的參數(shù)已經(jīng)被初始化妻柒,可以隨時(shí)運(yùn)行
運(yùn)行(started): 表示插件已經(jīng)在運(yùn)行狀態(tài)
停止(stopped): 表示插件已經(jīng)停止運(yùn)行
插件的接口提供了所有插件對(duì)外提供的基本操作。
get_state:獲取插件當(dāng)前的狀態(tài)
name:獲取插件名稱
set_program_options:設(shè)置插件所需要的參數(shù)
initialize:插件初始化
startup:插件運(yùn)行
shutdown:插件停止
2耘分、插件模板
EOS插件實(shí)現(xiàn)所用技術(shù)比較復(fù)雜举塔,代碼也比較晦澀。首先EOS插件有三個(gè)層次求泰,第一層是接口abstract_plugin央渣,為插件提供統(tǒng)一的訪問(wèn)接口;第二層是模板層plugin,根據(jù)插件類型去推演出插件自己的父類;第三層EOS插件根據(jù)自己的業(yè)務(wù)去實(shí)現(xiàn)具體的方法渴频。
EOS插件使用了C++的多態(tài)機(jī)制痹屹,父類只提供接口,不同的子類根據(jù)自己業(yè)務(wù)實(shí)現(xiàn)自己方法。其次EOS插件使用模板機(jī)制,根據(jù)不同的插件類去推演出自己的父類崭倘,EOS插件采用代理的設(shè)計(jì)模式完成實(shí)現(xiàn)業(yè)務(wù)方法與接口方法不同。
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插件中比較難理解的是插件模板機(jī)制楼肪,插件用自己的類型傳入模板中去推演自己的父類,導(dǎo)致無(wú)法理解(自己怎么能夠繼承自己呢)惹悄。不理解的原因在于不明白模板的運(yùn)行是在編譯器春叫,只要提供與模板接口一樣就可以,第二、類的聲明和類的定義在編譯器的操作是不一樣的暂殖。類的聲明后就可以創(chuàng)建指針价匠,任何類型的指針都可以編譯器得到其所占空間的大小。而類的定義就需要確定類的實(shí)現(xiàn)具休是什么樣子呛每,編譯器才能在編譯期確定類對(duì)象的大小踩窖,才不使編譯器報(bào)錯(cuò)。
3晨横、舉個(gè)例子-chain_plugin模板實(shí)現(xiàn)
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;
};