c++ - 初始化容器中对象的正确方法/模式

标签 c++ design-patterns c++11 initialization

我有一个模板化容器World,其中包含ObjectWorld 是在Object 上执行的工作流程。

通常我使用默认构造函数构造Object,但现在我需要从运行时提供一些参数。

我的问题是找到一种良好且干净的方法来使World使用给定值初始化Object

建议的解决方案 1

现在我已经创建了一种 Init 对象,它在 main.cpp 中保存初始化 Object 所需的值我设置了它,并在 Object 的构造函数中将其传递给 Init 的实例来执行初始化。它看起来像这样:

对象.h:

class Object; //forward declaration
struct Init {
  void Initialize(Object& object);
  int property1;
  double property2;
  string property3;
};

class Object{
 static Init init;
public:
 Object(){
   init.Initialize(*this);
 }
};

这样World不需要了解Object的构造知识,只需使用默认构造函数即可。

我不喜欢这个解决方案,因为它过于复杂,我正在寻找更好的解决方案。

第一季度。这是一个好的解决方案吗?它有名称吗(也许它是一种设计模式或反模式)?

建议的解决方案 2

我想我可以通过一些 World::init_objects 方法传递构造 Object 所需的参数。我相信从 c++11 开始这是可能的。 init_objects 方法可以是构造对象的可变参数模板。

建议的示例:

template<typename Object>
class World {
  std::vector<Object> _internal_container;
  size_t _size;
public:
  World(size_t size) : _size(size) { _internal_container.reserve(_size); };

  template<typename... Args>
  init_objects(const Args&... args){
    for(size_t i = 0; i < _size; ++i) _internal_container.emplace_back( Object(args) );
  }
}

这样我就没有额外的对象,并且World也不需要知道任何关于Object内部结构的信息。 main.cpp 需要调用 init_objects 而不是设置 Object::init 实例。

第二季度。这种方法是否可行,或者有什么重大缺点吗? (我想我更喜欢它,但也许这是一个很快就会碰壁的坏主意。)

第三季度。有没有更好的办法,我没有想到。也许这是一个简单的问题,具有首选的设计模式/实现。

我认为我提出的解决方案并不是相互排斥的,但我想清理我凌乱的代码,并选择一个好的、干净的、漂亮的代码实践来接受并坚持下去。

最佳答案

Q1. Is this a good solution, and does this have a name (perhaps it's a design pattern, or antipattern)?

是的。这(或多或少)是工厂对象模式(尽管在工厂对象实现的规范示例中,对象不“知道”工厂是什么 - 对象中没有对工厂的静态引用)。

Q2. Is such approach feasible, or has any major drawbacks? (I think I like it better, but maybe it is a bad idea that will hit a wall soon.)

解决方案是可行的。一个缺点是您在要在对象中设置的参数/值上实现模板的方式。

考虑这个实现:

template<typename Object>
class World {
    std::vector<Object> objects;
    // size_t _size; // << size removed
public:
    World(size_t size) : objects(size) // use default constructor 
    {}

    template<typename P> // << changed here
    void apply(P predicate) { // << change here
        std::for_each(objects.begin(), objects.end(), predicate); // << and here
    }
};

客户端代码:

World w{10}; // create 10 objects with default values
w.apply([](object& o) { o.set_xyz(10); o.set_yyy(20); });

通过这个解决方案,您可以以模块化方式使用 apply (您可以注入(inject)初始化或其他任何东西)。

作为旁注,还可以考虑使用工厂函数(针对世界,而不是内部对象)基于已构造的对象 vector 创建世界对象。这将消除对对象进行额外初始化的需要(即,它不会影响世界的公共(public)接口(interface))并将世界转变为异常安全对象(可能仍然需要上面的 apply 方法,对于其他用途):

template<typename O> class World {
    std::vector<O> objects;
public:
    World(std::vector<O> obj) : objects{std::move(obj)} {}
    // eventually define apply function here
};

template<typename O, typename... Args>
World<O> make_world(size_t size, const Args&... args){
    std::vector<O> objects{size};
    for(auto& o: objects)
    { /* set arguments here */ }
    return World<O>{std::move(objects)};
}

编辑:具体的 make_world 示例,不需要封装对象的默认构造函数:

struct Length { int length; Length(int l) : length{l} {} };

World<Length> make_length_world(size_t size, int default_length)
{
    std::vector<Length> values;
    for(size_t index = 0; index < size; ++index)
        values.emplace_back(default_length);
    return World<Length>{std::move(values)};
}

struct Person {
    std::string first_name; std::string last_name;
    Person(std::string first, std::string last)
    : first_name{std::move(first)}, last_name{std::move(last)} {}
};


World<Person> make_robert_paulson_world(size_t size)
    // "his name is Robert Paulson"
    // so don't pass name as parameter
{
    std::vector<Person> values;
    for(size_t index = 0; index < size; ++index)
        values.emplace_back("Robert", "Paulson");
    return World<Person>{std::move(values)};
}

关于c++ - 初始化容器中对象的正确方法/模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21829976/

相关文章:

c++ - QMainWindow 打开后从静态函数运行 QDialog 对象

design-patterns - Actor 模式——它到底是什么组成的

c# - 使用存储库模式实现 Web 服务的正确方法是什么

c++ - 将函数绑定(bind)到类型的更好语法?

c++ - 异步返回 void 类型的 future 而不是预期类型

c++ - 如何在 C++ 中将图像从 .bmp 转换为 .png

c++ - 使用 OpenGL 显示两个对象。纹理未按预期运行

c++ - 将 STL 容器与 boost 范围适配器一起使用时出现 value_type 错误

c++ - 在 C++ 中使用 MinGW 工具包含多个类/.o 文件

php - 内部工厂与外部工厂