DDD: how to keep an object of complex value unchanged?

I would like to model Address as an object of value. Since it is good practice to make it unchanged, I decided not to provide any setter that could modify it later.

A common approach is to pass data to the constructor; however, when the value object is quite large, it can become quite bloated:

 class Address { public function __construct( Point $location, $houseNumber, $streetName, $postcode, $poBox, $city, $region, $country) { // ... } } 

Another approach, which should contain arguments in the form of an array, leading to the creation of a clean constructor, but this can ruin the implementation of the constructor:

 class Address { public function __construct(array $parts) { if (! isset($parts['location']) || ! $location instanceof Point) { throw new Exception('The location is required'); } $this->location = $location; // ... if (isset($parts['poBox'])) { $this->poBox = $parts['poBox']; } // ... } } 

It also looks a bit unnatural for me.

Any tips on how to properly implement an object with a fairly large value?

+6
source share
3 answers

The main problem with a large list of parameters is the readability and the danger that you will mix parameters. You can solve these problems using the Template Builder , as described in Effective Java . This makes the code more readable (especially languages โ€‹โ€‹that do not support named and optional parameters):

 public class AddressBuilder { private Point _point; private String _houseNumber; // other parameters public AddressBuilder() { } public AddressBuilder WithPoint(Point point) { _point = point; return this; } public AddressBuilder WithHouseNumber(String houseNumber) { _houseNumber = houseNumber; return this; } public Address Build() { return new Address(_point, _houseNumber, ...); } } Address address = new AddressBuilder() .WithHouseNumber("123") .WithPoint(point) .Build(); 

Benefits:

  • Parameters
  • called so that they are more readable
  • harder to mix house number with region
  • can use your own order of parameters
  • optional parameters may be omitted

One of the drawbacks that I can think of is that forgetting to specify one of the arguments (for example, not calling WithHouseNumber ) will result in a run-time error, and not when compiling a temporary error when using the constructor. You should also consider using additional Value objects, such as PostalCode, for example (as opposed to passing a string).

In a related note, sometimes business requirements require a change in part of the Value object. For example, when the address was originally entered, the street number may have been spelled out and should be corrected. Since you modeled the address as an immutable object, it does not have a setter. One possible solution to this problem is to introduce the "No Side Effects" function in the address value object. The function will return a copy of the object itself, with the exception of the new street name:

 public class Address { private readonly String _streetName; private readonly String _houseNumber; ... public Address WithNewStreetName(String newStreetName) { // enforce street name rules (not null, format etc) return new Address( newStreetName // copy other members from this instance _houseNumber); } ... } 
+12
source

This is a common problem with Driven Driven development examples. There is no domain expert, and this is the person who will tell you what the address and its requirements are. I suspect a domain expert will tell you that the address does not have a period. You may be able to create a point from an address, but it does not require a point. Also P.O. The field will not be a single value in the address. You may need a mailbox address class (POBoxAddress). I declare this because this class looks like it was defined by the developer and not by the domain delivery or invoicing service. Speaking with a domain expert, you can reduce the number of parameters of your constructor.

second
You can start grouping parameters as value objects. You can create a City value object. This may require a city, region / state and country. I would think that the name of the city means little if I do not know the Region and the country. Saying Paris means nothing but Paris, Illinois, USA or Paris, Ile de France, FR gives you the whole picture. Thus, it will also reduce the counter of counters to the Address object.

If you go down the DDD road, find a domain expert for the domain you are coding, you should not be an expert. Sometimes problems cannot be fixed with code or a great design template.

0
source

immutable is suitable for parallel computing, without locking and without locking, unchanged for high performance and good scalability.

so that the Value object can work better in a parallel system, include in a distributed system, replace the old VO with a new VO, do not need to be updated, therefore, do not block.

-1
source

Source: https://habr.com/ru/post/897248/


All Articles