我有两个选择。 要么做出接受它的构造有很多争论的一类,或者创造了很多的setter方法和init方法。 我不知道这是最好的选择,应一些参数的构造函数中被接受,而其他人可以通过制定者可以手动设置? 还是我过想这?
这是一个相关的问题,也由我: 成员名称和构造函数的参数名之间的冲突 。
我有两个选择。 要么做出接受它的构造有很多争论的一类,或者创造了很多的setter方法和init方法。 我不知道这是最好的选择,应一些参数的构造函数中被接受,而其他人可以通过制定者可以手动设置? 还是我过想这?
这是一个相关的问题,也由我: 成员名称和构造函数的参数名之间的冲突 。
如果你创建一个对象后,你必须调用set
或init
到实际使用它......好吧,这只是一个可怕的设计。
如果对象是使用没有一些成员初始化你希望他们的方式,你可以稍后进行设置。
这里的指导原则是- 如果你创建了一个对象,你应该能够使用它没有做任何其他类型的初始化 。
假设你有10个面,10个转角,一个颜色,一个名字,可以连接到不同的形状。 构造函数应该是这样的:
MyShape(Point c1, Point c2,...., Point c10, Color c, Name n)
正如你所看到的,我省略了连接的形状,因为它可以合理地设置为NULL
如果当前对象未连接。 然而,在没有任何其他参数,对象是无效的,所以他们应该在构造函数中进行设置。
一种可能的过载(alternitively默认参数)可以是:
MyShape(Point c1, Point c2,...., Point c10, Color c, Name n,
MyShape* connectedShape /*=NULL*/)
你应该对所有需要保存为会员提供的构造函数的参数类不变 。 换句话说,对象应该是从创建它,直到它被破坏的瞬间有效和一致的状态。 其它所有东西都呼吁烦恼。
话虽这么说,让步有时进行,例如在需要虚拟方法,以提供特定类型的初始化被称为层次结构的情况下。 通常情况下,这可以通过模板类的使用来避免/方法(即静态多态性 )
如果有类成员不影响班级不变,它们可以在以后通过制定者或其他方法来设置。
生成器模式将有助于在这里也尽量合并的参数来让他们的建设者的建立过程中意义
它,而取决于你在做什么。 通常最好把事情在构造函数中,因为这些帮助塑造对象如何在其生命周期以后使用。 还可以有一次对象被创建(如计算因子或文件名),这可能意味着你必须提供的功能来重置对象更改值的影响 - 很凌乱。
有时有提供其(调用纯虚会使其难以从初始化构造函数直接时),但是你必须保持它增加了更多的复杂性对象状态的记录构造后调用初始化函数的参数。
如果对象是一个无状态的笔直数据容器然后存取函数可能是确定的,但他们补充大量的维护开销,却很少反正所有使用。
我倾向于使用在构造函数中设置的值,然后将访问器和何时允许你只读到,您可能需要参数的访问。
这取决于你的架构和工具:
如果您打算开发/原型的大型OO-层次,我很不愿意通过构造函数传递大量的信息,如果你没有一个良好的IDE /编辑器。 在这种情况下,你可能最终得到了很多工作,每一步重构,这可能会导致错误,而不是由编译器捕获。
如果你打算使用一个很好的整合组对象(例如,通过强大的使用设计模式),不跨越一个大的层次,而是有很强的iteraction,通过构造函数传递更多的数据是一件好事,因为改变一个对象的构造函数不打破所有的孩子构造函数。
如果需要设置并不能给出一个默认值,使其在构造函数中所需的。 你知道它的方式将实际设置。
如果不需要设置,可以给出一个默认值,使为它的制定者。 这使得构造简单了很多。
例如,如果您有一个发送电子邮件一类,可能在构造函数中所要求的“收件人”字段,但一切可以在setter方法进行设置。
我的经验指出我在构造函数中,而不是getter和setter有争论。 如果你有很多的参数,它暗示而要求/强制性的有构造函数的参数可选的人可以默认。
作为一个经验法则,有很多的构造函数的参数是一个类,做太多的迹象,所以首先尝试它分成小班。
然后尝试一些参数分组成自己的,简单的,每个构造更小的类或结构。
如果你有合理的默认值,你可以使用一个构造函数,只为绝对必须构建一个新的对象时,可以给定的值提供参数,然后添加setter方法,或使用复制“启动器”对象的静态功能,改变它的一部分正在进行中。 这样,你总是有一致的对象(不变量OK),以及较短的构造函数或函数调用。
我同意棘轮怪物的建议,建造者模式的不同之处在于存在一个权衡典型的建造者模式没有提供任何编译时检查,以确保所有的参数都被包括在内,你可以用最终完全/不正确建对象。
这是一个足以让我的问题,我做一个编译时检查版本,可能会为你做的工作,如果你能原谅额外的机械。 (当然也有优化将不得不为好)
#include <boost/shared_ptr.hpp>
class Thing
{
public:
Thing( int arg0, int arg1 )
{
std::cout << "Building Thing with \n";
std::cout << " arg0: " << arg0 << "\n";
std::cout << " arg1: " << arg1 << "\n";
}
template <typename CompleteArgsT>
static
Thing BuildThing( CompleteArgsT completeArgs )
{
return Thing( completeArgs.getArg0(),
completeArgs.getArg1() );
}
public:
class TheArgs
{
public:
int arg0;
int arg1;
};
class EmptyArgs
{
public:
EmptyArgs() : theArgs( new TheArgs ) {};
boost::shared_ptr<TheArgs> theArgs;
};
template <typename PartialArgsClassT>
class ArgsData : public PartialArgsClassT
{
public:
typedef ArgsData<PartialArgsClassT> OwnType;
ArgsData() {}
ArgsData( const PartialArgsClassT & parent ) : PartialArgsClassT( parent ) {}
class HasArg0 : public OwnType
{
public:
HasArg0( const OwnType & parent ) : OwnType( parent ) {}
int getArg0() { return EmptyArgs::theArgs->arg0; }
};
class HasArg1 : public OwnType
{
public:
HasArg1( const OwnType & parent ) : OwnType( parent ) {}
int getArg1() { return EmptyArgs::theArgs->arg1; }
};
ArgsData<HasArg0> arg0( int arg0 )
{
ArgsData<HasArg0> data( *this );
data.theArgs->arg0 = arg0;
return data;
}
ArgsData<HasArg1> arg1( int arg1 )
{
ArgsData<HasArg1> data( *this );
data.theArgs->arg1 = arg1;
return data;
}
};
typedef ArgsData<EmptyArgs> Args;
};
int main()
{
Thing thing = Thing::BuildThing( Thing::Args().arg0( 2 ).arg1( 5 ) );
return 0;
}