我一直在阅读和搜索网络一段时间,但还没有找到一个好的解决方案。这是我想要做的:
我正在编写一个定义抽象基类的库 - 我们称之为IFoo。
class IFoo {
public:
virtual void doSomething() = 0;
virtual ~IFoo() {}
};
该库还为此定义了几个实现——我们称它们为FooLibOne和FooLibTwo。
为了封装创建过程并根据某些运行时参数决定使用哪个具体实现,我使用工厂FooFactory将 std::string 映射到工厂方法(在我的情况下为 boost::function,但这不应该是重点这里)。它还允许注册新的工厂方法。它看起来像这样:
class FooFactory {
public:
typedef boost::function<IFoo* ()> CreatorFunction;
IFoo* create(std::string name);
void registerCreator(std::string name, CreatorFunction f);
private:
std::map<std::string, CreatorFunction> mapping_;
};
现在,我直接在FooFactory的构造函数中添加了库提供的实现(FooLibOne、FooLibTwo)——因此它们始终可用。一些库代码使用 FooFactory 来初始化某些对象等。到目前为止,我一直避免对工厂使用单例模式,因为 tee 模式经常被争论,我不确定单例模式的不同实现如何工作结合可能的多个共享库等。
然而,在工厂之间传递可能有点麻烦,我仍然认为,这是单例模式可能有用的场合之一。特别是如果我考虑到,库的用户应该能够添加更多的IFoo实现,这些实现也应该可供(已经存在的)库代码访问。当然,依赖注入——意味着我通过构造函数传递了一个工厂的实例——可以做到这一点(现在就这样做)。但是,如果我想更加灵活并引入第二层动态对象创建,这种方法就会失败。含义:我想在动态创建的对象(比如抽象基类IBar - BarOne和BarTwo - 再次通过工厂BarFactory)。
假设BarOne需要一个IFoo对象,但BarTwo不需要。无论如何,我仍然必须将 FooFactory 提供给BarFactory,因为其中一个IBar实现可能需要它。拥有全球可访问的工厂将缓解这个问题,并且我不会被迫预见特定接口的实现可能需要哪些工厂。此外,我可以直接在实现的源文件中注册创建方法。
FooFactory::Instance().registerCreator("new_creator", boost::bind(...));
既然我认为这是一个好主意,那么实施它的正确方法是什么?我打算采用模板化方法,例如Modern C++ Design中的SingletonHolder(另请参见Loki库)来包装工厂。但是,我宁愿将其实现为 Meyer 的 Singleton。但我仍然认为共享库会有问题。该解决方案应与 GCC(最好是 MSVC)一起使用。从设计的角度来看,我也对其他想法持开放态度,但请避免常见的“单身人士是邪恶的”-咆哮。;-)
提前致谢。