gpt4 book ai didi

c++ - 为有条件编译的产品实现工厂模式

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:01:28 24 4
gpt4 key购买 nike

我想以一种允许我在不引入类型依赖性的情况下编译代码的方式实现工厂(或其他一些模式)。

enum CarType
{
BMW,
PORSCHE,
MERC
};

class CarFactory
{
public:
static Car* create(CarType type)
{
switch(type)
{
case BMW : return new BMWCar();
case PORSCHE : return new PorscheCar();
default : return new MercCar();
}
}
};

当我编译 CarFactory 时,我需要将 BMWCar、PorscheCar 和 MercCar 作为我的编译/链接单元的一部分。

根据我的代码库设置方式,我们可能只想发布 BMWCar,或者其中的两个或全部三个。所以,我不能使 create() 依赖于类型。

我如何为此调整工厂模式?另外,我想避免执行 ifdefs,因为这只是我的问题的一个示例。真正的代码库是巨大的,不是 ifdef 代码的实用解决方案。

更新:另外,我不允许使用:

  • 模板
  • 必须符合c++ 98标准
  • 不能使用提升

这主要是由于客户构建工具链的限制。我别无选择。

最佳答案

我通常会做类似的事情:

class CarFactory
{
public:
static void RegisterCar(CarType t, std::function<Car*()> f)
{
getMap().emplace(t, f);
}
static Car* create(CarType type)
{
return getMap().at(type)();
}
private:
static std::unorderd_map<CarType, std::function<Car*()> >& getMap()
{
static std::unorderd_map<CarType, std::function<Car*()> > m;
return m;
}
};

并且在每个类的实现中:

 class BMWCar : public Car
{
struct Init
{
Init()
{
CarFactory::RegisterCar(BMW, [](){return new BMWCar(); });
}
};
static Init initializeBmwCar;
/** .. */
};

/*** BMWCar.cpp ***/
BMWCar::Init BMWCar::initializeBmwCar;

这是有效的,因为每个类型在静态初始化期间使用 static Init 对象初始化自己的工厂。

这段代码中的巨大痛苦是为了避免初始化顺序的失败:一个天真的实现会简单地在 CarFactory 中使用静态映射。遗憾的是,无法保证 BMWCar::initializeBmwCar 构造函数会在 CarFactory 中的 map 之后运行。有时某些编译器可能会工作,有时它可能会崩溃。所以想法是使用一个静态函数(getMap)和一个静态变量(m),保证在第一次getMap时被初始化> 被调用。

我知道 clang/llvm 使用这种模式来注册优化过程。

另一个更复杂但更灵活的解决方案是设计一个插件系统,其中每个 DLL 实现一个 car 类型并导出一个 CreateCar 函数。

然后您可以在初始化期间通过动态加载库并调用GetProcAddress/dlsym 收集所有这些CreateCar

这两种解决方案在 Windows 上都可能很难实现,因为(除非 Car 是抽象的)基础 Car 实现需要放在它自己的库中,并且每个插件 dll需要与该库链接。

关于c++ - 为有条件编译的产品实现工厂模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31797099/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com