views:

550

answers:

5

I'm learning about DDD, and have come across the statement that "value-objects" should be immutable. I understand that this means that the objects state should not change after it has been created. This is kind of a new way of thinking for me, but it makes sense in many cases.

Ok, so I start creating immutable value-objects.

  • I make sure they take the entire state as parameters to the constructor,
  • I don't add property setters,
  • and make sure no methods are allowed to modify the content (only return new instances).

But now I want to create this value object that will contain 8 different numeric values. If I create a constructor having 8 numeric parameters I feel that it will not be very easy to use, or rather - it will be easy to make a mistake when passing in the numbers. This can't be good design.

So the questions is: Are there any other ways of making my immutable object better.., any magic that can be done in C# to overcome a long parameter list in the constructor? I'm very interested in hearing your ideas..

UPDATE: Before anyone mentions it, one idea has been discussed here: http://stackoverflow.com/questions/263585/immutable-object-pattern-in-c-what-do-you-think

Would be interested in hearing other suggestions or comments though.

+7  A: 

Use a builder:

public class Entity
{
   public class Builder
   {
     private int _field1;
     private int _field2;
     private int _field3;

     public Builder WithField1(int value) { _field1 = value; return this; }
     public Builder WithField2(int value) { _field2 = value; return this; }
     public Builder WithField3(int value) { _field3 = value; return this; }

     public Entity Build() { return new Entity(_field1, _field2, _field3); }
   }

   private int _field1;
   private int _field2;
   private int _field3;

   private Entity(int field1, int field2, int field3) 
   {
     // Set the fields.
   }

   public int Field1 { get { return _field1; } }
   public int Field2 { get { return _field2; } }
   public int Field3 { get { return _field3; } }

   public static Builder Build() { return new Builder(); }
}

Then create it like:

Entity myEntity = Entity.Build()
                   .WithField1(123)
                   .WithField2(456)
                   .WithField3(789)
                  .Build()

If some of the parameters are optional you won't need to call the WithXXX method and they can have default values.

Andrew Kennan
This seams to be a good option. Some extra code, but I think you gain some clarity. I will try this out.
Torbjørn
The downside with this is that you don't get the benefit of C# 3 object initializers. That can be fixed by having properties (as well as the methods for pre-C#3 clients): new Entity.Builder { Field1=123, Field2=456, Field3=789 }.Build()
Jon Skeet
Thanks Jon - I hadn't thought of that approach as I'm stuck in 1.1 and 2.0 world at work and only recently started playing with c# 3 at home.
Andrew Kennan
In the example I don't like the two different methods both called Build(). What would be some better names you think?
Torbjørn
Maybe GetBuilder()?
phillipwei
+2  A: 

Off the top of my head, two different answers come to mind ...

... the first, and probably simplest, is to use an object factory (or builder) as a helper that ensures you get things right.

Object initialization would look like this:

var factory = new ObjectFactory();
factory.Fimble = 32;
factory.Flummix = "Nearly";
var mine = factory.CreateInstance();

... the second is to create your object as a conventional, mutable, object with a Lock() or Freeze() function. All of your mutators should check to see if the object has been locked, and throw an exception if it has.

Object initialization would look like this:

var mine = new myImmutableObject();
mine.Fimble = 32;
mine.Flummix = "Nearly";
mine.Lock(); // Now it's immutable.

Which method to take depends a lot on your context - a factory has the advantage of being convenient if you have a series of similar objects to construct, but it does introduce another class to write and maintain. A lockable object means there is only one class, but other users might get unexpected runtime errors, and testing is harder.

Bevan
Note that in both these cases, C# 3.0 makes the initialization more compact.
Jon Skeet
A: 

At the moment, you'd have to use a constructor with lots of args, or a builder. In C# 4.0 (VS2010), you can use named/optional arguments to achieve something similar to C# 3.0 object-initializers - see here. The example on the blog is:

  Person p = new Person ( forename: "Fred", surname: "Flintstone" );

But you can easily see how something similar can apply for any constructor (or other complex method). Compare to the C# 3.0 object-initializer syntax (with a mutable type):

 Person p = new Person { Forename = "Fred", Surname = "Flintstone" };

Not much to tell them apart, really.

Jon Skeet has posted some thoughts on this subject too, here.

Marc Gravell
+1  A: 

Although it is probably part of the domain of what you are doing, and thus my suggestion may be invalid, what about attempting to break down the 8 parameters into logical groups?

Whenever I see heaps of parameters, i feel like the object/method/contructor ought to be simpler.

Chii
I've already done a lot of that, and using the principle that no class should have more than 7 or 8 fields I've ended up with several value objects with pretty logical groupings. But a valuable comment, Chii.
Torbjørn
+1  A: 

I have been boggled with the same question as complex constructors is also bad design to me. I am also not a big fan of the builder concept as it seems like too much extra code to maintain. What we need is popsicle immutability, which means that an object starts out as mutable where you are allowed to use the property setters. When all properties are set there must be a way of freezing the object into an immutable state. This strategy is unfortunately not supported natively in the C# language. I therefore ended up designing my own pattern for creating immutable objects as described in this question:

http://stackoverflow.com/questions/263585/immutable-object-pattern-in-c-what-do-you-think

Anders Hejlsberg is talking about support for this type of immutability from 36:30 in the following interview:

Expert to Expert: Anders Hejlsberg - The Future of C#

Lars Fastrup