EOS插件继承机制讲解

字数 627阅读 102

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插件根据自己的业务去实现具体的方法。


image.png

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;
};