对象构造函数“设置”成语

时间:2011-10-28 15:00:17

标签: c++ constructor idioms

我记得在很长一段时间内读过有关复杂对象配置情况下C ++的构造函数的习惯。它特别有用,因为它有助于为一些讨厌的概念启用RAII,这些概念具有方式太多(通常是冲突的)选项。

这是一个简单的例子。假设您要为Win32 API窗口编写包装类。要初始化窗口,您需要知道窗口样式,扩展窗口样式,初始窗口位置,初始窗口大小等。在窗口样式中,许多选项冲突且无法一起设置。将所有这些方法放在Window类中是禁止的,并且阻止定义正确的类不变量。使用临时对象对所有参数值进行分组可能有助于防止不可能的配置,并为Window类定义一个不错的不变量(例如,它始终保持有效的窗口句柄)。

class Settings
{
    ::DWORD myBasicStyles;     // takes lots of different flags.
    ::DWORD myExtentedStyles;  // even more flags.
    ::POINT myInitialLocation;
    ::SIZE myInitialSize;
    // lots more...
public:
    void setInitialPosition ( int x, int y );
    void setInitialSize ( int top, int left );
    void useSpecialBorder ();
    // lots more...
    void enableTransparency ();
    // lots more...
};

class Window
{
    ::HWND handle;
public:
    // map settings unto the horrible list of many parameters expected
    // by "CreateWindowEx()", then invoke it to allocate the resource.
    Window ( const Settings& settings );
};

// calling code.
int main ()
{
    Settings settings;
    settings.setInitialPosition(0, 0);
    settings.setInitialSize(500, 300);
    settings.setInitiallyVisible(true);
    Window window(settings);
    // ... rest of application ...
}

但是,我找不到我读这个的页面,甚至找不到它的名字。任何人都可以告诉我这是什么叫做,并且可能链接到关于这个主题的好资源吗?

3 个答案:

答案 0 :(得分:3)

看起来像混合物。

Settings对象是使用Named Parameter Idiom创建的。虽然通常你会看到它返回一个自己的引用,所以你可以链接它们。

struct Builder {
  Builder &one(int val) { one_ = val_; return *this; }
  Builder &two(int val) { two_ = val_; return *this; }
  int one;
  int two;
};

void foo() {
  Builder builder().one(1).two(2);
}

Settings正在使用作为 Encapsulated Context Pattern。链接有点罗嗦。基本思想是你只需将参数放在一个对象中并传递该对象。

在一个有点相关的问题上,我认为它包含了任何内容。然而,这可能仅仅是人们超载词语的含义。 :)

答案 1 :(得分:1)

我在互联网上找到了名字Named Parameter Idiom。它略有不同,但用途相同。

答案 2 :(得分:0)

如果你真的想要一个名字,我宁愿把它称为 参数对象 成语。与其背后的想法相比,这个名称实际上并不重要。

这个想法是将一组相关数据与一个包含所有这些数据的对象组合在一起。将这些参数转换为对象是值得的,因为:

  • 它减小了参数列表的大小,并且很难理解长参数列表。
  • 新对象上定义的访问器也使代码更加一致,这再次使其更容易理解。
  • 更重要的是,它可以帮助您识别这组数据的常见行为,以便您可以进入新类。通过将这些行为移动到新对象中,您可以识别重复的代码并将其删除。此外,您对数据有很好的封装。一旦对数据的任何操作的实现发生变化,只有一个地方可以更改,客户端不会受到影响。