简体   繁体   English

如何实例化一个大的不可变类型?

[英]How to instantiate a large immutable type?

I have a type with about 40 properties (all value types) that represents a type of transaction for my business. 我有一个类型,有大约40个属性(所有值类型),代表我的业务的一种交易。 An instance of this class corresponds to a row in my database. 此类的实例对应于我的数据库中的一行。 I would like to keep my class immutable since it will only ever be used for read operations, but I am not sure how to go about setting 40 properties during initialization. 我想保持我的类不可变,因为它只会用于读取操作,但我不知道如何在初始化期间设置40个属性。

Typically I use constructor initialization for immutable types, but I would like to avoid writing a constructor with 40 parameters. 通常我对不可变类型使用构造函数初始化,但我想避免编写带有40个参数的构造函数。 The setters for my properties are currently private though I am willing to change with good enough reason. 我的房产的安装人员目前是私人的,但我愿意以足够的理由改变。 Is there a common way to handle this situation or a better way to approach the problem? 是否有一种常见的方法来处理这种情况或更好的方法来解决问题?

Your problem isn't so much a constructor with 40 arguments, but a class with 40 fields. 你的问题不是一个有40个参数的构造函数,而是一个有40个字段的类。

I'd recommend breaking this down. 我建议打破这个。 Are any of the fields related in some way? 是否有任何相关领域? If so, group them into a common object (eg EmailInfo), then have your big object just reference the grouping objects. 如果是这样,将它们分组到一个公共对象(例如EmailInfo),然后让你的大对象引用分组对象。

// Instead of this:
foo.EmailHeader
foo.EmailSubject
foo.Email...

// Do this:
foo.Email.Header
foo.Email.Subject

Once your class has fewer direct properties, creating a constructor that takes those grouping objects isn't so terrible. 一旦你的类具有较少的直接属性,创建一个获取这些分组对象的构造函数并不是那么糟糕。

Quick point. 快点。 You mentioned your setters on the object are private. 你提到你对象的setter是私有的。 If that is the case then your object is not immutable (otherwise setters couldn't exist). 如果是这种情况,那么您的对象不是不可变的(否则setter不存在)。 At best your object is read only. 最好你的对象是只读的。

For a true immutable object there is no choice but to have the constructor take in all of the values necessary to initialize the object. 对于一个真正的不可变对象,别无选择,只能让构造函数接受初始化对象所需的所有值。 The best way to reduce the number of parameters in the constructor is to group the values into bigger objects which are then passed to the constructor. 减少构造函数中参数数量的最佳方法是将值分组为更大的对象,然后将这些对象传递给构造函数。 Although I wouldn't do that unless the values are otherwise logically related. 虽然我不会这样做,除非这些值在逻辑上是相关的。

If your immutable type does truly need the 40 values and they are otherwise unrelated, the best approach is to have a constructor with 40 values. 如果你的不可变类型确实需要40个值而且它们不相关,那么最好的方法是使用一个具有40个值的构造函数。 That or further break down the big immutable object. 那还是进一步打破了大不可变对象。

I like the approach of using a mutable object to instantiate an immutable object; 我喜欢使用可变对象来实例化不可变对象的方法; the mutable object is just for tidy passing of options. 可变对象只是为了整理选项。 One example of this in the .NET framework is ProcessStartInfo . .NET框架中的一个例子是ProcessStartInfo

class XInfo {
  public int A;
  public int B;
}

class X {
  public X (XInfo i) {
    // you can transform the data/layout from i any way you need
    ..
  }
}

new X(new XInfo() {
  A = 42
})

While I'll hold my tongue about the '40 properties', I find the above approach works pretty well. 虽然我会对'40属性'保持缄默,但我发现上述方法效果很好。 An added bonus is the XInfo and the internal structure used in X can be entirely different, as long as you can provide a sane mapping. 另外一个好处是XInfoX使用的内部结构可以完全不同,只要您可以提供合理的映射。

If i go by your words "but I am not sure how to go about setting 40 properties during initialization.", it appears that your problem is a class with too many fields/properties. 如果我按照你的说法“但我不确定如何在初始化期间设置40个属性。”,看来你的问题是一个具有太多字段/属性的类。 Doesnt seem to be a problem of making it immutable, because you already know how to do that. 似乎不是让它变得不可变的问题,因为你已经知道如何做到这一点。

I would suggest (like others), Refactor and Extract Class. 我会建议(像其他人一样),Refactor和Extract Class。

As an alternative, you can make your class derive from freezable , I think this may be the solution you are searching for. 作为替代方案,您可以使您的类派生自freezable ,我认为这可能是您正在寻找的解决方案。 You can Instatiate the object, set the values, then set it frozen. 您可以对对象进行Instatiate,设置值,然后将其设置为冻结。 Once you set it frozen the class is 'read only'. 一旦你将它设置为冻结,该类就是“只读”。

I would suggest putting the parameters into one or more structures, and having the object hold those structures. 我建议将参数放入一个或多个结构中,让对象保存这些结构。 Nesting objects would be possible, but would add more overhead than nesting structures. 嵌套对象是可能的,但是会比嵌套结构增加更多的开销。

As an alternative, you could create an abstract base class with "readonly mustoverride" versions of all your properties. 作为替代方案,您可以使用所有属性的“readonly mustoverride”版本创建一个抽象基类。 From this, derive a mutable and immutable object class. 由此,派生出一个可变且不可变的对象类。 The immutable one can accept the base class in its constructor, and use all the readonly properties to build the new object. 不可变的可以在其构造函数中接受基类,并使用所有readonly属性来构建新对象。 The mutable class can provide a means of writing the properties using methods, read-write properties with different names from the readonly versions, etc. 可变类可以提供使用方法编写属性的方法,具有来自只读版本的不同名称的读写属性等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM