Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
jijinlong edited this page Nov 14, 2016 · 15 revisions

##C++依赖注入实现 我们的目标就是 能够影藏具体的实现,并且可以抽选相关的实现,使用时只约定接口即可。

 // 定义的接口
 IAction action; 
 // 选择相关的实现,在配置文件中通过ActionImp 抽选相关的实现为action赋值
 action.imp("ActionImp"); 
 //注意这里的-> 他是会调用的具体实现的方法
 action->doSometing(); 

怎么能做到这点呢?我们一步步来,先实现基础的Interface类

template<typename T>
class Interface {
public:
 // 重载-> 调用子类相关函数
 T * operator->() 
 {
 if (_buffer == 0) return 0;
 return static_cast<T*>((void*)_buffer);
 }
 Interface()
 {
 _buffer = 0;
 }
 virtual ~Interface()
 {
 // 注意并不是直接delete _buffer ,若是将无法调用实现的析构
 if (_buffer) delete static_cast<T*>((void*)_buffer); _buffer = 0;
 }
protected:
 void* _buffer; // 具体实现类 所使用 的空间
};

为什么不用 纯虚函数呢? 对象在使用时必须有实现,不然C++无法分配内存,所有必须是个包含空实现的虚函数来做,我们是需要在运行期指定实现的。我们定义IAction 来继承Interface 类,Interface类帮我们实现了->重载 可以让C++为我们自动调用实现类的方法。

class IAction:public Interface<IAction> {
public:
 virtual void doSometing(){}; // 空实现 必须是虚函数
 virtual ~IAction(){}; // 务必加上
 void imp(const char *name); // 指定使用实现的类
};

我们来定义一个实现

class ActionImp:public IAction {
public:
 void doSometing(){
 printf("dosometing"); // 就输出字符串
 }
};

我们怎么将 IAction 与 ActionImp 对应呢?简单的方式,为IAction 提供一个方法,在这个方法里 指定具体的实现

void IAction::imp(const char *name)
{
 if (name == "ActionImp")
 {
 _buffer = new ActionImp(); // 根据字符串来产生不同的实现
 }
}

这也是一种方法,很LOW,如果你觉得够用就这样用,但是我们希望代码少做这些 If Else 写一个基础的工厂来生产这些对象

void IAction::imp(const char *name)
{
 _buffer = ObjectFactory::instance()->create(name); // 这样是不是更好? 
}

如何实现这样的ObjectFactory 呢?

最简单的办法 就是 ObjectFactory 根据名字分发生产对象,就是if else 的方式,我们这里通过hashmap 存放相关实现,通过名字抽选出具体的产出类,然后clone 生成当前对象

class Implement{
public:
 // 容器中存放相关不同实现的对象
 virtual void *clone(){return 0;};
}
template<typename T>
class Implement : public Implement{
public:
 T *clone()
 {
 return new T();
 } 
}; 
// ActionImp 需要 继承ImplementCreator 
// 其实就是为了你少写个 clone() 函数 你 继承Implement 实现 clone 函数也可以 
class ActionImp:public IAction,public ImplementCreator<ActiomImp> {
// 具体的实现
};
class ObjectFactory : public Singleton<ObjectFactory>{
public:
 Implement* create(const char *name)
 {
 auto it = imps.find(name);
 if (it != imps.end())
 {
 return it->second->clone();
 }
 return 0;
 }
 //初始化的时候放入具体的实现
 void init()
 {
 _imps["ActionImp"] = new ActionImp();
 }
private:
 std::unordered_map<std::string,Implement*> _imps;
}

上面的Singleton的代码如下

template<typename T>
class Singleton {
public:
 static T* instance()
 {
 return &o;
 }
private:
 static T o;
}
template<typename T>
T Singleton<T>::o;

以上就是factory 的代码实现了名字与实现的绑定,但是我们如何从配置文件中指定具体的实现呢?我们需要将ObjectFactory::init里实现的注册方式,通过配置去指定,也是我们为什么没用if-else 来产出对象的原因,如果你项目不需要XML去管理对象的产生也行,单我们这里通过XML来加载,一个名字可以对应其他的实现,ActionImp 可能对应的是 ActionImp_0的实现,引入了别名机制

class ObjectFactory : public Singleton<ObjectFactory>{
public: 
 void init()
 {
 _imps["ActionImp_0"] = new ActionImp();
 _imps["ActionImp_1"] = new ActionImp();
 XmlObjectFactory::createAllCreator(); // 通过XmlObjectFactory 来指定当前名字 所对应的真正的Implements 
 }
 Implement* create(const char *name)
 {
 auto it = _alias_imps.find(name);
 if (it != _alias_imps.end())
 {
 auto real_it = _imps.find(it->second);
 if (real_it != _imps.end())
 {
 return real_it->second->clone();
 } 
 } 
 return 0;
 }
private:
 static std::unordered_map<std::string,Implement*> _imps; // 当前存储
 std::unordered_map<std::string,std::string> _alias_imps; // 当前别名 
};
std::unordered_map<std::string,Implement*> ObjectFactory::imps;

配置

 <config> 
 <bean name="ActionImp" class="ActionImp_0"/> <!--当前指定 ActiomImp 的实现为ActionImp_0-->
 </config>

解析配置构建 ActiomImp 与 ActiomImp_0 等得键值对即可. 每次扩展实现的时候都需要在Init里填写代码,也是蛮费时的,我们需要外部注册。利用全局对象来外部构建

template<typename T>
class AutoRegisterCreator{
public:
 AutoRegisterCreator(const char *name)
 {
 ObjectFactory::imps[name] = new T();
 }
};
#define IMP(name,CLASS) AutoRegisterCreator<T> CLASS#TT(name) 
//会在ObjectFactory::instance()->init 之前调用这个构造函数 从而完成自动外部注册,不用再init里加注册代码了

这里就基本完成的csspring的框架.那么csspring的框架将如何使用呢?

// 初始化ccspring
 ccs::ObjectFactory::instance()->init();
// 需要定义接口
 class YourInterface : public Interface<YourInterface> {
 public:
 virtual void doAction(){};
 };
// 约定实现的字符串
 YourInterface logic;
 logic.imp("YourImp");
// 定义实现
 class YourImplement:pulic Implement<YourImplement> {
 public:
 void doAction(){}
 };
 IMP("YourImp_0",YourImplement); // 指定当前实现的名字 
// 使用接口
 YourInterface your;
 your->doAction(); // 调用实现的具体方法
// 定义配置
 <config><bean name="YourImp" class="YourImp_0"/></config>

为啥如此复杂的使用和创建对象呢? 为的使项目的去依赖,如果你觉得需要 可以试试。

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /