0

After searching SOF for related questions and finding something roughly similar for PHP, but still not satisfying, here's my question.

Problem: using an inner static builder class feels like too much typing. I want to keep some properties immutable but I don't want to use constructors with a significant number of arguments, i.e. only those that are immutable.

Solution: Create a class with a constructor that takes all the required fields and setter methods for properties that aren't required. Chain the call to allow the following pattern.

var product = new Product("Car")
.withColor(Color.Black)
.withGears(5);

Do you consider this an anti-pattern? What benefit does the classic builder-pattern have over this? Read only fields would still be part of the constructor arguments.

My first post to SOF, thanks!

1 Answers1

0

If you are developing a Domain Model this kind of solution violates the separation of concerns and muddles the definition of a particular part of the Model (a Product in your case).

A Product class represents a Product from the business domain that you are modeling. A Product class instance will be a concrete product, for example a book, a radiator, a bike etc. The Product class instance should have responsibilies for containing and managing it's life-cycle and keeping it's invariants.

Methods like WithColor and WithGears in Product muddle what it represents.

The creation of a Product is a separate responsibility. It can be given to a separte Class for example a ProductFactory or a ProductBuilder or it can be geven to the Class itself by the Constructor or static Factory methods.

Many different things can affect how you choose to create your Products.

  • How complex the task is?
  • How many variations of products are there? Can you have a separate factory method for reusing the creation of products and making this easier for client code?

If creating of Product instances is simple then you need only a constructor.

If you notice that thre are too many different ways to create a Product you can use a factory. For example:

class ProductFactory {

  public Product CrateBook(string title, ....);
  public Product CrateFictionalBook(string title, ....);
  public Product CrateScifiBook(string title, ....);
  public Product CrateMagazine(string title, ....);
}

These methods will create the most common types of books by setting the appropriate parameters so that your client code doesn't have to do it. As a consequence you have a more readable code, as the method names give you information of what type of book you are creating instead of having just a constructor.

This is more intention revealing and shorter:

book = ProductFactory.CreateScifiBook("Killer robots", ...);

than this:

book = new Product(BookTypes.Scifi, new ISBN(), "Killer robots", ...);

it's true that you have to write more classes and more methods, but if you have to create lots of products in the code you will save yourself a lot of typing.

In your case you have lots of different combinations between the properties of the Product class. Creating different methods like in the ProductFactory that create books, will lead to the explosion of methods that will make the code harder to write and undertand. These methods are not composable. In this case use the builder pattern to make the creation of a product easier and more readable like in your example.

If your system isn't very complex it's not necessary to add additional classes. If you system grows, adding factories and builder can reduce typing and make code more readable and explicit.

If you haven't read Domain Driven Design from Eric Evans I highly recommend it. It dicusses in detail how to build Domain Models.

expandable
  • 2,180
  • 7
  • 15