Reputation: 884
According to DDD principles, it's often advised that value objects be used to encode values which don't have a life cycle of their own, but are merely values. By design, such objects are made immutable. They often replace primitives, which makes the code more semantic and error-safe.
The rationale is very sensible, but sometimes it leads to some cumbersome operations. For example, consider the case where an address is encoded as a value object along the lines of:
class Address extends ValueObject {
public Address(String line1, String line2, String postalCode, String String country) {
...
}
...
}
In an application, it wouldn't be unusual for a user to change only one field of an address. In order to achieve that in code, one would have to do something like:
String newCity = ...;
Address newAddress = new Address(
oldAddress.getLine1(),
oldAddress.getLine2(),
oldAddress.getPostalCode(),
newCity,
oldAddress.getCountry());
This could lead to some very repetitive and overly verbose code. What are some good strategies for avoiding this, while keeping immutable value objects?
My own ideas:
Private setters, which could enable helper methods like this:
public Address byChangingPostalCode(String newPostalCode) {
Address newAddress = this.copy();
newAddress.setPostalCode(newPostalCode);
return newAdress;
}
A downside is that the object now isn't immutable anymore, but as long as that's kept private, it shouldn't be a problem, right…?
Make the value object a full-fledged entity instead. After all, the need for fields to be modified over a longer time indicates that it does have a life cycle. I'm not convinced by this though, as the question regards developer convenience rather than domain design.
I'll happily receive your suggestions!
UPDATE
Thanks for your suggestions! I'll go with private setters and corrective methods.
Upvotes: 1
Views: 463
Reputation: 81
I would solve this with derive methods:
Address newAddress = oldAddress.derive( newPostalCode);
Address newAddress = oldAddress.derive( newLine1 );
And so on...
Upvotes: 0
Reputation: 17683
Private setters, which could enable helper methods like this:
This is my preferred solution for changing a Value object. The naming of the method should be from the ubiquitous language but this can be combined to a team/programming language convention. In PHP there is a known convention: immutable command method names start with the word "with". For example withCorrectedName($newName)
.
The object must not be fully constant but only act as such in order to be considered immutable.
Make the value object a full-fledged entity instead.
It wouldn't be a ValueObject anymore, so don't!
Upvotes: 1
Reputation: 57299
There's nothing wrong with having immutable values return other immutable values.
Address newAddress = oldAddress.correctPostalCode(...);
This is my preferred approach within the domain model.
Another possibility is to use a builder
Address new Address = AddressBuilder.from(oldAddress)
.withPostalCode(...)
.build()
I don't like that one as much, because build
isn't really part of the ubiquitous language. It's a construction I'm more likely to use in a unit test, where I need a whole address to talk to the API but the test itself only depends on a subset of the details.
Upvotes: 3