使用C ++中的多个库的单身人士和工厂

时间:2012-04-01 17:27:03

标签: c++ singleton shared-libraries factory-pattern object-construction

我一直在网上阅读和搜索一段时间,但还没有找到一个很好的解决方案。这就是我想要做的事情:

我正在编写一个定义抽象基类的库 - 我们称之为 IFoo

class IFoo {
    public:
        virtual void doSomething() = 0;
        virtual ~IFoo() {}
};

该库还定义了几个实现 - 让我们称之为 FooLibOne FooLibTwo

为了封装创建过程并根据某些运行时参数决定使用哪个具体实现,我使用工厂 FooFactory 将std :: string映射到工厂方法(在我的例子中是boost: :功能,但这不应该是这里的重点)。它还允许注册新的工厂方法。它看起来像这样:

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初始化某些对象等。到目前为止,我已经避免使用Singleton模式用于工厂,因为tee模式经常被争论,我不确定,Singleton模式的不同实现如何工作与可能的多个共享库等结合使用。

然而,绕过工厂可能有点麻烦,我仍然认为,这是Singleton模式可以很好用的一个例子。特别是如果我考虑的话,库的用户应该能够添加更多 IFoo 的实现,这些实现也应该可以被(现有的)库代码访问。当然,依赖注入 - 意思是我通过构造函数传递工厂的实例 - 可以做到这一点(现在就做)。但是如果我想要更灵活并引入第二层动态对象创建,这种方法就会失败。含义:我想在动态创建的对象中动态创建对象(参见上文)(比如抽象基类的实现 IBar - BarOne BarTwo - 再次通过工厂 BarFactory )。

让我们说 BarOne 需要 IFoo 对象,但 BarTwo 则不需要。在任何情况下,我仍然必须向 BarFactory 提供 FooFactory ,因为其中一个 IBar 实现可能需要它。拥有全球可访问的工厂可以缓解这个问题,我不会被迫预测,特定接口的实现可能需要哪些工厂。另外,我可以直接在实现的源文件中注册创建方法。

FooFactory::Instance().registerCreator("new_creator", boost::bind(...));

既然我认为这是一个好主意,那么实施它的正确方法是什么?我想采用模板化的方法,比如来自 Modern C ++ Design SingletonHolder (另见Loki库)来包装工厂。但是,我宁愿把它作为迈耶的单身人士来实现。但我仍然认为共享库会出现问题。该解决方案应与GCC(最好是MSVC)一起使用。从设计的角度来看,我也对其他想法持开放态度,但请避免常见的“单身人士是邪恶的”。 ; - )

提前致谢。

1 个答案:

答案 0 :(得分:0)

希望76行代码能说几句话 - (使用这些功能的C ++ 11版本而不是增强版本,但无论如何它们几乎相同)

我会将 factory(ies)的定义和 creators 的定义放在相同(或附近)的范围内,以便每个创建者都可以“看到”他们的任何依赖工厂 - 避免过多地绕过工厂,避免单身人士

汽车与汽车警报器:

class ISiren {};
class Siren : public ISiren 
{
public:
    Siren() { std::cout << "Siren Created" << std::endl; }
};

class ICar{};
class EstateCar : public ICar 
{
public:
    EstateCar() { std::cout << "EstateCar created" << std::endl;}
};
class PoliceCar : public ICar 
{
    std::shared_ptr<ISiren> siren;
public:
    PoliceCar( std::shared_ptr<ISiren> siren)
        : siren( siren ) 
    {
        std::cout << "PoliceCar created" << std::endl;
    }
};

工厂:

typedef std::function< std::shared_ptr<ICar> () > CreatorType;

class CarFactory
{
    std::map<std::string, CreatorType> creators;
public:
    void AddFactory( std::string type, CreatorType func )
    {
        creators.insert( std::make_pair(type, func) );
    }

    std::shared_ptr<ICar> CreateCar( std::string type )
    {
        CreatorType& create( creators[type] );
        return create();
    }
};

class SirenFactory
{
public: // Simple factory creating 1 siren type just for brevity
    std::shared_ptr<ISiren> CreateSiren() { return std::make_shared<Siren>(); }
};

“工厂根”(主要功能,无论工厂在何处定义):

int main()
{
    CarFactory car_factory; // Car factory unaware of Siren factory
    SirenFactory siren_factory;

    auto EstateCarLambda = []() { 
        return std::make_shared<EstateCar>(); 
    }; // Estate car lambda knows nothing of the Siren Factory

    auto PoliceCarLambda = [&siren_factory]() {
        return std::make_shared<PoliceCar>( siren_factory.CreateSiren() );
    };  // Police car creation lambda using the Siren Factory

    car_factory.AddFactory( "EstateCar", EstateCarLambda );

    car_factory.AddFactory( "PoliceCar", PoliceCarLambda );

    std::shared_ptr<ICar> car1 = car_factory.CreateCar( "EstateCar" );
    std::shared_ptr<ICar> car2 = car_factory.CreateCar( "PoliceCar" );
}