且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在C++中正确实现工厂方法模式

更新时间:2022-01-26 01:31:34

首先,有这样的情况对象构建是一项复杂的任务足以证明它的提取是合理的另一堂课.

First of all, there are cases when object construction is a task complex enough to justify its extraction to another class.

我认为这一点是不正确的.复杂性并不重要.相关性是什么.如果一个对象可以一步构建(不像在构建器模式中那样),那么构造函数就是正确的地方.如果你真的需要另一个类来执行这项工作,那么它应该是一个从构造函数中使用的辅助类.

I believe this point is incorrect. The complexity doesn't really matter. The relevance is what does. If an object can be constructed in one step (not like in the builder pattern), the constructor is the right place to do it. If you really need another class to perform the job, then it should be a helper class that is used from the constructor anyway.

Vec2(float x, float y);
Vec2(float angle, float magnitude); // not a valid overload!

对此有一个简单的解决方法:

There is an easy workaround for this:

struct Cartesian {
  inline Cartesian(float x, float y): x(x), y(y) {}
  float x, y;
};
struct Polar {
  inline Polar(float angle, float magnitude): angle(angle), magnitude(magnitude) {}
  float angle, magnitude;
};
Vec2(const Cartesian &cartesian);
Vec2(const Polar &polar);

唯一的缺点就是看起来有点冗长:

The only disadvantage is that it looks a bit verbose:

Vec2 v2(Vec2::Cartesian(3.0f, 4.0f));

但好处是您可以立即看到您使用的坐标类型,同时您不必担心复制.如果你想复制,而且成本很高(当然,通过分析证明),你可能希望使用类似 Qt 的共享类以避免复制开销.

But the good thing is that you can immediately see what coordinate type you're using, and at the same time you don't have to worry about copying. If you want copying, and it's expensive (as proven by profiling, of course), you may wish to use something like Qt's shared classes to avoid copying overhead.

对于分配类型,使用工厂模式的主要原因通常是多态性.构造函数不能是虚拟的,即使可以,也没有多大意义.使用静态或堆栈分配时,您不能以多态方式创建对象,因为编译器需要知道确切的大小.所以它只适用于指针和引用.从工厂返回引用也不起作用,因为虽然技术上可以通过引用删除对象,但它可能相当混乱且容易出错,请参阅返回C++引用变量的做法是不是邪恶的?例如.所以指针是唯一剩下的东西,这也包括智能指针.换句话说,工厂在与动态分配一起使用时最有用,因此您可以执行以下操作:

As for the allocation type, the main reason to use the factory pattern is usually polymorphism. Constructors can't be virtual, and even if they could, it wouldn't make much sense. When using static or stack allocation, you can't create objects in a polymorphic way because the compiler needs to know the exact size. So it works only with pointers and references. And returning a reference from a factory doesn't work too, because while an object technically can be deleted by reference, it could be rather confusing and bug-prone, see Is the practice of returning a C++ reference variable, evil? for example. So pointers are the only thing that's left, and that includes smart pointers too. In other words, factories are most useful when used with dynamic allocation, so you can do things like this:

class Abstract {
  public:
    virtual void do() = 0;
};

class Factory {
  public:
    Abstract *create();
};

Factory f;
Abstract *a = f.create();
a->do();

在其他情况下,工厂只是帮助解决小问题,例如您提到的过载问题.如果可以以统一的方式使用它们会很好,但它可能是不可能的,这并没有太大的伤害.

In other cases, factories just help to solve minor problems like those with overloads you have mentioned. It would be nice if it was possible to use them in a uniform way, but it doesn't hurt much that it is probably impossible.