2017-10-19 321 views
2

以此示例代码为例,我希望 button1和button2是两个单独的对象。[Boost] :: DI从注入器创建唯一的shared_ptr对象

#include <iostream> 
#include <memory> 
#include "di.hpp" 
namespace di = boost::di; 

struct CommandQueue { 
    void addCommand() {} 
}; 

struct Control { 
    Control(CommandQueue &cq) : cq(cq) { 
     static int sid{}; 
     id = ++sid; 
    } 

    CommandQueue& cq; 
    int id{}; 
}; 

int main() { 

    auto injector = di::make_injector(di::bind<CommandQueue>().in(di::singleton)); 

    auto button1 = injector.create<std::shared_ptr<Control>>(); 
    auto button2 = injector.create<std::shared_ptr<Control>>(); 

    std::cout << "button1->id = " << button1->id << std::endl; 
    std::cout << "button2->id = " << button2->id << std::endl; 

    return 0; 
} 

电流输出是:

button1-> ID =

button2-> ID =

相反的意图:

button1-> ID =

button2-> ID =

卸下从CommandQueue单的di::singleton寿命范围也不能解决问题。 我知道shared_ptr的生命周期默认情况下是单例,但我认为它被引用到注入的依赖关系中,而不是用create创建的实际对象。

+0

什么是addCommand' – sehe

+0

的'相关性这只是一个占位符,以证明使用CommandQueue作为单身,但即使没有这些代码仍然创造1对象而不是2 – Dado

回答

1

实际上最简单的事情可能是

auto button1 = injector.create<Control>(); 
auto button2 = injector.create<Control>(); 

std::cout << "button1.id = " << button1.id() << std::endl; 
std::cout << "button2.id = " << button2.id() << std::endl; 

打印

button1.id = 1 
button2.id = 2 

如果必须具有共享指针,接下来最简单的事情将是

auto button1 = std::make_shared<Control>(injector.create<Control>()); 
auto button2 = std::make_shared<Control>(injector.create<Control>()); 

std::cout << "button1->id = " << button1->id() << std::endl; 
std::cout << "button2->id = " << button2->id() << std::endl; 

概念你想要一个控制工厂,而不是控制。所以,你应该考虑从依赖容器创建一个工厂:

#include <boost/di.hpp> 
#include <iostream> 
#include <memory> 
namespace di = boost::di; 

struct CommandQueue { 
    void addCommand() {} 
}; 

struct Control { 
    Control(CommandQueue &cq) : _cq(cq), _id(idgen()) { } 

    int id() const { return _id; } 

    struct Factory { 
     Factory(CommandQueue& cq) : _cq(cq) {} 
     CommandQueue& _cq; 

     template <typename... Args> 
     auto operator()(Args&&... args) const { 
      return std::make_shared<Control>(_cq, std::forward<Args>(args)...); 
     } 
    }; 
    private: 
    static int idgen() { static int sid{}; return ++sid; } 
    CommandQueue &_cq; 
    int _id{}; 
}; 

int main() { 
    auto injector = di::make_injector(di::bind<CommandQueue>().in(di::singleton)); 

    auto factory = injector.create<Control::Factory>(); 
    auto button1 = factory(); 
    auto button2 = factory(); 

    std::cout << "button1->id = " << button1->id() << std::endl; 
    std::cout << "button2->id = " << button2->id() << std::endl; 
} 
+0

谢谢,我不想在我们的lib中打破OCP,所以将shared_ptr转换为对象并不是一个好的选择,我已经考虑过像您在第二个示例中所建议的“裸”make_shared,但是我不确定这是否是DI的最佳实践,最后是的,我已经将真正的代码封装到工厂中了,但是我仍然想知道如果使用DI,我会在创建的左侧调用make_shared,我不想这样做,以避免深层复制,并不得不写迭代ctor。基本上我只是想重新确保我没有做任何错事:) – Dado

+0

你刚刚告诉我,我浪费了我的时间下载增强DI,阅读文档(和代码,转瞬即逝),并提出了建议? – sehe

+0

嗯不,你为什么会这么想?我想详细说明我的思维过程,我不确定是否要编辑原始问题以附加信息或答复作为注释 – Dado