通用工厂方法和可变参数模板的问题

aby*_*s.7 8 c++ unit-testing factory-pattern variadic-templates c++11

我想创建类似通用工厂方法的东西 - 看看这个:

template <class BaseType>
class Factory {
  public:
    template <class ... Args>
    static BaseType* Create(const Args& ... args) {
      return new DerivedType(args ...);
    }
};
Run Code Online (Sandbox Code Playgroud)

其中的DerivedType某些其他类型来自BaseType不同的地方并在其他地方定义.

问题在于存储DerivedType.我想这样做,例如,像这样:

void f() {
  // Derived type may have more than one constructor,
  // that's why I suggest using of the variadic templates.
  BaseType* ptr1 = Factory<BaseType>::Create("abc", 5, 10.);
  BaseType* ptr2 = Factory<BaseType>::Create();
  ...
}

...

Factory<BaseType>::SetType<MyDerivedType>();
f();

Factory<BaseType>::SetType<YourDerivedType>();
f();
Run Code Online (Sandbox Code Playgroud)

我可以设置不同的派生类型,但所有这些类型在编译时都是已知的.我想不出适当的技术来做到这一点.

问题:你能告诉一个吗?


这样做的理由(因此,原始问题,如果有人建议问题是它自己的XY问题) - 是一种单元测试一些棘手的代码部分的能力.例如,如果我有一个代码:

...
Shuttle* shuttle1 = new ShuttleImpl("Discovery", Destination::Moon);
Shuttle* shuttle2 = new ShuttleImpl();
...
Run Code Online (Sandbox Code Playgroud)

而且每次运行单元测试时我都不想真正构造穿梭机:

class Shuttle: public Factory<Shuttle> { ... }
...
Shuttle* shuttle1 = Shuttle::Create("Discovery", Destination::Moon);
Shuttle* shuttle2 = Shuttle::Create();
...
Run Code Online (Sandbox Code Playgroud)

所以,在单元测试中,我可以做到:Shuttle::SetType<TestShuttle>();.

可能会有更多"可测试"的类,这就是为什么我需要一个通用工厂的所有类:

class Car: public Factory<Car> { ... }
class Driver: public Factory<Driver> { ... }
...
Run Code Online (Sandbox Code Playgroud)

Cou*_*per 1

不是完整的答案,但类模板的Create静态函数模板应该是:

template <class BaseType>
class Factory {
  public:
    template <class... Args>
    static BaseType* Create(Args&&... args) {
      return new DerivedType(std::forward<Args>(args)...);
    }
};
Run Code Online (Sandbox Code Playgroud)

另请参见何时使用 std::forward 转发参数?


编辑:

为什么第二个模板参数不能解决您的问题?

例如:

template <class Base, class Derived>
class Factory {
  public:
    template <class... Args>
    static Base* Create(Args&&... args) {
      return new Derived(std::forward<Args>(args)...);
    }
};
Run Code Online (Sandbox Code Playgroud)

代替

Factory<BaseType>::SetType<MyDerivedType>();
f();

Factory<BaseType>::SetType<YourDerivedType>();
f();
Run Code Online (Sandbox Code Playgroud)

你可以写:

Factory<MyBase, MyDerived1> factory1;
Factory<MyBase, MyDerived2> factory2;

auto object1 = factory1::Create(1, "a");
auto object2 = factory2::Create(1.2, "abc");
Run Code Online (Sandbox Code Playgroud)