2009-04-15 67 views

回答

18

如果需要在对象上设置很多东西,这是一个可用的模式。

class Foo 
{ 
     int x, y, z; 
public: 
     Foo &SetX(int x_) { x = x_; return *this; } 
     Foo &SetY(int y_) { y = y_; return *this; } 
     Foo &SetZ(int z_) { z = z_; return *this; } 
}; 

int main() 
{ 
     Foo foo; 
     foo.SetX(1).SetY(2).SetZ(3); 
} 

这种模式取代了构造函数,需要三个整数:

int main() 
{ 
     Foo foo(1, 2, 3); // Less self-explanatory than the above version. 
} 

,如果你有一个数字,并不总是需要设置的值是非常有用。

仅供参考,此类技术的更完整示例在C++ FAQ Lite中被称为“Named Parameter Idiom”。

当然,如果你使用这个命名参数,你可能想看看boost::parameter。或者你可能不会......

+0

最近我一直对这种技术很感兴趣。看看是否有人提出任何缺点会很有趣。 – 2009-04-15 17:18:17

+0

有趣。我没有把它当作复杂构造函数的替代品。这种技术可以减少大量的构造函数重载。 – 2009-04-15 17:22:02

+1

有些事情你无法做到这一点,你可以使用构造函数(例如,初始化常量和引用) – Eclipse 2009-04-15 17:24:12

0

我不这么认为。通常情况下,你认为'setter'对象就是这么做的。

此外,如果你只是设置了对象,你还没有指向它的指针吗?

2

不是所有的setters,但其中一些可能会返回对对象的引用有用。

那种

a.SetValues(object)(2)(3)(5)("Hello")(1.4); 

我用这一次,很久以前就建立SQL表达式生成器负责处理所有的问题,转义和其他东西。

SqlBuilder builder; 

builder.select(column1)(column2)(column3). 
    where("=")(column1, value1) 
       (column2, value2). 
    where(">")(column3, 100). 
    from(table1)("table2")("table3"); 

我在10分钟内无法再现源代码。所以实施就在幕后。

10

,如果你想链setter函数可以返回一个参考this称这样在一起:

obj.SetCount(10).SetName("Bob").SetColor(0x223344).SetWidth(35); 

我个人认为代码更难比其他阅读:

obj.SetCount(10); 
obj.SetName("Bob"); 
obj.SetColor(0x223344); 
obj.SetWidth(35); 
2

如果你的动机与链接有关(比如Brian Ensink的建议),我会提供两条评论:

1. 如果哟你会发现自己经常一次设置很多事情,这可能意味着你应该产生一个structclass,它保存所有这些设置,以便它们都可以一次通过。下一步可能是在对象本身中使用此structclass ...但由于您使用getter和setter,因此如何在内部表示它的决定对于类的用户来说是透明的,所以这个决定将会更多地涉及班级的复杂程度。

2. 一个替代方案是创建一个新对象,改变它并返回它。这在大多数类型中都是低效和不适当的,特别是可变类型。但是,尽管它在许多语言的字符串类中使用,但这是人们有时会忘记的选项。

2

此风格的典型用途是用于对象构造。

Person* pPerson = &(new Person())->setAge(34).setId(55).setName("Jack"); 

代替

Person* pPerson = new Person(34, 55, "Jack"); 

使用第二多的传统风格,如果传递给构造函数的第一个值是年龄或ID人们可能忘记呢?这也可能导致基于某些属性的有效性的多个构造函数。

使用第一种方式可能会忘记设置一些对象属性,并且可能会导致对象未完全构建的错误。 (稍后会添加一个类属性,但并非所有的构建位置都会更新以调用所需的设置器。)

随着代码的发展,我真的很喜欢这样一个事实,即我可以使用编译器来帮助我找到所有的位置在更改构造函数的签名时创建对象。因此,我更喜欢使用常规的C++构造函数来覆盖这种风格。

  • 您可以将现场/属性添加到表/类,它是NULL:

    这种模式可能在维持根据相似于许多数据库应用程序使用的规则及其随时间的数据模型的应用程序运行良好默认。 (因此,升级现有数据只需要在数据库中添加一个新的NULL列。)

  • 未更改的代码应该仍然与添加此NULL字段的工作相同。
3

IMO制定者是一个代码味道,通常表明两种情况之一:

制作殷海涛小题大做

,如果你有一个这样的类:

class Gizmo 
{ 
public: 
    void setA(int a) { a_ = a; } 
    int getA() const { return a_; } 

    void setB(const std::string & b) { v_ = b; } 
    std::string getB() const { return b_; } 
private: 
    std::string b_; 
    int a_; 
}; 

...而这些数值真的就是这么简单,那么为什么不让数据成员公开?:

class Gizmo 
{ 
public: 
    std::string b_; 
    int a_; 
}; 

...简单得多,如果数据就是这么简单你失去什么。

另一种可能性是,你可能是

制作小题大做输出A殷海涛

很多倍的数据并不那么简单:也许你必须改变多个值,做一些计算,通知一些其他的对象;谁知道什么。但是,如果数据不够平凡,你确实需要setter &获取器,那么它也是不平凡的,也需要错误处理。所以在这些情况下,你的获得者应该返回某种错误代码或者做其他事情来指示发生了不好的事情。

如果你喜欢这个链接调用起来:

A.doA().doB().doC(); 

...和DOA()失败,你真要叫DOB()和DOC()呢?我对此表示怀疑。

相关问题