Reputation: 849
Say you have a class called Person
, and a Person
has attributes such as name
, id
, age
, etc. Instead of setting these values in the constructor, one does
new Person().withName("Lorem").withId("1234").withAge(29)
Where a with
method is a call to a set
method, and returns the object, e.g.,
public Person withAge(int age) {
this.setAge(age);
return this;
}
On a current project, I see a lot of code like this, often with 5-10 chained calls to different with
methods. What are the benefits of doing this instead of setting these values in the constructor?
Upvotes: 4
Views: 381
Reputation: 895
Its all about readability and fluent interfaces.
While your example is not a very good one for fluent interfaces, you can find on in the Java part of the wikipedia article::
Author author = AUTHOR.as("author");
create.selectFrom(author)
.where(exists(selectOne()
.from(BOOK)
.where(BOOK.STATUS.eq(BOOK_STATUS.SOLD_OUT))
.and(BOOK.AUTHOR_ID.eq(author.ID))));
Fluent interfacing is a very advanced topic in the API design, that often comes with some kind of Builder pattern (to avoid too big and too many constructors) or Facade pattern (to avoid hard to understand, mostly internal APIs).
A pretty fluent API normally require a deep understanding of your requirements and a very good planning/preparation phase.
Note that using fluent APIs is closely connected to writing a DSL. Here you have an example by Martin Fowler and an extended, really good explanation of fluent interfacing, its advantages, disadvantages, theories, etc.
Upvotes: 2
Reputation: 5087
One advantage i see is readability.
If we extend the example
new Person()
.withName("Lorem")
.withId("1234")
.withAge(29)
.withHeight(170)
.withWeight(75)
.withTaxId("1234");
If we didn't use this pattern and used the constructor pattern we would end up lots of parameter without any description about them when using them.
new Person("Lorem","1234",29,170,75,"1234");
Upvotes: 2
Reputation: 14572
What are the benefits of doing this instead of setting these values in the constructor?
1) Overloading
You can manage the number of value you want to set easily, if you have a lot of parameter to set, but some are optionnal, you don't have to create specific constructor or passing null
value.
new Person("name", 19);
new Person("name", 19, address);
new Person("name", 19, phone);
(those are bad example ;) )
In you case, you just have to call the method you need (same with setters).
2) Identitication
Also, having a lot of parameters in a method/constructor tend to be difficult to read, to identify each parameter context
new Person("frank", "John", "Emma");
person.withName("frank").withFather("john").withMother("Emma");
Passing parameter to a method/constructor is nameless, you have to check the signature to understand what you are passing. With that notation, you have a more verbose and readable code. (again, same with setters).
3) Chainable setter The same would be done with setters but without the chainable feature you have here.
person.setName("name");
person.setAge(19);
person.withName("name").withAge(19);
Other than the readability, I don't think there is really some improvement, the chain need the method to return the instance itself, that give a redondant code in the class itself (return this;
).
Upvotes: 3
Reputation: 5676
There seem to be 2 major advantages :
1.) Flexibility : With this pattern, you can basically choose fields to populate and not populate. While with constructors, you need to have multiple constructors to achieve the same. As in Person
can be
new Person().withName("Loren")
Or it can be
new Person().withName("Loren").withAge(30)
with everything else null/default.
In case of constructor initialization, you had to have 2 constructors for both of these.
public Person(String name){
//code
}
public Person(String name, String age){
//code
}
2.) As mentioned by other answers, readability.
new Person().withName("Loren").withAge(30).withId(567)
is more readable than
new Person("Loren", 30, 567)
Upvotes: 1