Just getting my head around the Builder pattern and I have a few (noob) questions. Mainly, why can't we just simplify the creation of a builder object?
Instead of this:
public final class Foo {
private final String name;
private final String description;
private Foo(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public static class Builder {
private String name;
private String description;
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setDescription(String description) {
this.description = description;
return this;
}
public Foo build() {
return new Foo(name, description);
}
}
}
//Use it
Foo f = new Foo.Builder().setName("test").setDescription("description").build();
Why not just use this?
public final class Foo {
private String name;
private String description;
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Foo setName(String name){
this.name=name;
return this;
}
public Foo setDescription(String description){
this.description=description;
return this;
}
}
//Use it
Foo f = new Foo().setName("test").set("description");
I see maybe the first one is used when you want to build an immutable object, but other than that why can't I just use the second one instead? It's far simpler. Please provide examples as much as possible.
Using your Second approach , i will be able to create a Object by doing.
Foo f = new Foo().setDescription("description");
Which means, We java created a object in your system without a name.
If we take another example which will be must self explanatory .
Employee emp = new Employee ().setDescription("manager");
Which means i hired a manager in a company without even know name.
Basically with Build() , we can also make sure all the required member variable are provided while creating a object. We can even do basic vaidation if needed.
public Foo build() {
if(name == null){
throw Exception();
else
return new Foo(name, description);
}
The builder pattern is useful when there are operations that are valid during construction that are not valid once the object is built.
Yes, this is most obviously the case for building immutable objects, but it also applies very often when only some aspects of the object are immutable. Common examples are:
Often the identifier for an object (a person's name, for example) is specified during construction, but is not allowed to change after that;
Injected dependencies, like the database to use, the log to use, etc., are often not allowed to change after construction;
Factories and strategies are often not allowed to change after construction, because the object expects consistency across all their outputs.
Also, sometimes a setter on a valid object would have an effect, like dispatching an event, for example, that you don't want to happen during construction. You can sometimes get around that via complicated rules like "don't attach listeners until you're finished setting stuff up", but complicated rules are to be avoided.
Your way is "JavaBeans Patterns", From effectice java item2:"JavaBean Patterns" construction is split across multiple calls, a
JavaBean may be in an inconsistent state partway
through its construction. The class does not have the option of
enforcing consistency merely by checking the validity of the
constructor parameters. Attempting to use an object when it’s in
an inconsistent state may cause failures that are far removed from
the code containing the bug and hence difficult to debug. A related
disadvantage is that the JavaBeans pattern precludes the
possibility of making a class immutable and
requires added effort on the part of the programmer to ensure
thread safety. "Builder Pattern" is thread safe and more readable.
you can use lombok #Builder annotation to make a class "Builder Pattern".
Related
I have a class that may have several enums within it.
Each enum is supposed to have a string value associated with each entry.
In order to achieve this, I have added a parametrized constructor,a supporting string class member and overridern the toString method.
However one can see that 50% of the code between my two enums are same. It's just the code to support mapping strings to the Enum values.
How can I move this code to a common place and avoid code duplication?
Edit: Use case is to easily obtain "New York" when I write America.STATES.NY.
Here's what I tried,
1) I tried using a common interface, but the constructors are different.
2) I tried using inheritance, but enums cannot be inherited
public class America {
public enum STATES {
NY("New York"), CA("California");
String displayName;
STATES(String displayName) {
this.displayName = displayName;
}
#Override
public String toString() {
return this.displayName;
}
}
public enum PROVINCES {
ON("Ontario"), QU("Qubec");
String displayName;
PROVINCES(String displayName) {
this.displayName = displayName;
}
#Override
public String toString() {
return this.displayName;
}
}
}
A typical phrase I like to use is "data isn't a part of behavior, and doesn't belong in the code". To be clear (and from my experience), it's much easier to adopt or translate a system that relies on the data for it being loaded from something rather than representing the data in hard-coded values.
public class Region {
private final String name;
public Region(String name) { this.name = name; }
public String getDisplayName() { return this.name; }
public String toString() { return getDisplayName(); }
}
public class Country {
//keeps a map/list of "regions", whether states or provinces or some other type
public Region getRegion(Object key); //lookup a region based on some key, I'll use strings here
}
Country america = /* a country supplied from somewhere */;
String name = america.getRegion("NY").getDisplayName(); //"New York"
This type of approach, while sub-optimal for hard-coded references in your code (like getRegion("NY")), is much more forgiving when you need to modify the data later or make a reference which is loaded from elsewheres (e.g. a user-supplied Region or lookup name). If you use a database, you can keep your code up-to-date without ever having to change the project, just the database itself. And in the end, since all of this data-related information is stored elsewheres, the overall amount of code to handle is vastly reduced.
You can also later add in something to support determining whether a given administrative region is a state or province or something else (which I think an enum is great for):
public enum RegionType {
STATE, PROVINCE, ADMIN_REGION, OTHER,
;
}
You can implement an EnumUtils class and add a static instance of it to every enum class. I implemented an example here: https://stackoverflow.com/a/48199147/7949301.
I have a huge (parent) POJO which is being used in some component. The POJO has individual fields as well as nested POJOs as well. Is it possible to determine what all fields/ nested fields from this POJO are being accessed in that component?
I was thinking about JUnits/ aspects but not sure if either would work. I've tried looking through SF/ and Google but could not find any relevant thread for this thing.
Say following is a sample POJO:
public class Student {
private String name;
private Date date;
private Subject subject;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
}
It has three fields name, date and subject, not all of which would be in use in my component. So I need to determine which are actually being used.
Edit:
Thanks Sharon for pointing out that the getter/setters were protected. I had just generated the class on the fly for the purpose of question and didn't notice the issue. Corrected now.
How the class is initialised: For the purpose of the component, objects will be created from Json/XML data and would have only getters being called.
As for static vs runtime analysis, I'd prefer to achieve it through static code analysis if that's possible otherwise runtime also is fine with me if that's easier.
As for using Decorator pattern, do we have anything without requiring existing code change? That's why I was thinking if JUnits could do this.
First of all, it is odd to see getter/setter methods that are protected. seems to me they need to be public?
Anyway, I would utilize the Decorator design pattern.
From the linked article:
The decorator design pattern allows us to dynamically add
functionality and behavior to an object without affecting the behavior
of other existing objects in the same class.
So, our decorated Student should inherit from the target class. All methods can log their usage and call super to invoke target operation. You didn't say how Student
is initialized, but anyway, you will want to modify that to create instances of LogUsageStudent
public class LogUsageStudent extends Student {
protected String getName() {
// log usage of getName()
return super.getName();
}
// etc
}
Foo foo = Foo.builder()
.setColor(red)
.setName("Fred")
.setSize(42)
.build();
So I know there is the following "Builder" solution for creating named parameters when calling a method. Although, this only seems to work with inner static classes as the builder or am I wrong? I had a look at some tutorials for builder pattern but they seem really complex for what im trying to do. Is there any way to keep the Foo class and Builder class separate while having the benefit of named parameters like the code above?
Below a typical setup:
public class Foo {
public static class Builder {
public Foo build() {
return new Foo(this);
}
public Builder setSize(int size) {
this.size = size;
return this;
}
public Builder setColor(Color color) {
this.color = color;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
// you can set defaults for these here
private int size;
private Color color;
private String name;
}
public static Builder builder() {
return new Builder();
}
private Foo(Builder builder) {
size = builder.size;
color = builder.color;
name = builder.name;
}
private final int size;
private final Color color;
private final String name;
}
Use composition. To make things easier and cleaner, do not replicate all attributes in source (Foo) and builder (Builder) class.
For example, have Foo class inside Builder instead of each of Foo attribute.
simple code snippet:
import java.util.*;
class UserBasicInfo{
String nickName;
String birthDate;
String gender;
public UserBasicInfo(String name,String date,String gender){
this.nickName = name;
this.birthDate = date;
this.gender = gender;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("Name:DOB:Gender:").append(nickName).append(":").append(birthDate).append(":").
append(gender);
return sb.toString();
}
}
class ContactInfo{
String eMail;
String mobileHome;
String mobileWork;
public ContactInfo(String mail, String homeNo, String mobileOff){
this.eMail = mail;
this.mobileHome = homeNo;
this.mobileWork = mobileOff;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("email:mobile(H):mobile(W):").append(eMail).append(":").append(mobileHome).append(":").append(mobileWork);
return sb.toString();
}
}
class FaceBookUser {
String userName;
UserBasicInfo userInfo;
ContactInfo contactInfo;
public FaceBookUser(String uName){
this.userName = uName;
}
public void setUserBasicInfo(UserBasicInfo info){
this.userInfo = info;
}
public void setContactInfo(ContactInfo info){
this.contactInfo = info;
}
public String getUserName(){
return userName;
}
public UserBasicInfo getUserBasicInfo(){
return userInfo;
}
public ContactInfo getContactInfo(){
return contactInfo;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("|User|").append(userName).append("|UserInfo|").append(userInfo).append("|ContactInfo|").append(contactInfo);
return sb.toString();
}
static class FaceBookUserBuilder{
FaceBookUser user;
public FaceBookUserBuilder(String userName){
this.user = new FaceBookUser(userName);
}
public FaceBookUserBuilder setUserBasicInfo(UserBasicInfo info){
user.setUserBasicInfo(info);
return this;
}
public FaceBookUserBuilder setContactInfo(ContactInfo info){
user.setContactInfo(info);
return this;
}
public FaceBookUser build(){
return user;
}
}
}
public class BuilderPattern{
public static void main(String args[]){
FaceBookUser fbUser1 = new FaceBookUser.FaceBookUserBuilder("Ravindra").build(); // Mandatory parameters
UserBasicInfo info = new UserBasicInfo("sunrise","25-May-1975","M");
// Build User name + Optional Basic Info
FaceBookUser fbUser2 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).build();
// Build User name + Optional Basic Info + Optional Contact Info
ContactInfo cInfo = new ContactInfo("xxx#xyz.com","1111111111","2222222222");
FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).
setContactInfo(cInfo).build();
System.out.println("Facebook user 1:"+fbUser1);
System.out.println("Facebook user 2:"+fbUser2);
System.out.println("Facebook user 3:"+fbUser3);
}
}
output:
Facebook user 1:|User|Ravindra|UserInfo|null|ContactInfo|null
Facebook user 2:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|null
Facebook user 3:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|email:mobile(H):mobile(W):xxx#xyz.com:1111111111:2222222222
Explanation:
FaceBookUser is a complex object with below attributes using composition:
String userName;
UserBasicInfo userInfo;
ContactInfo contactInfo;
FaceBookUserBuilder is a static builder class, which contains and builds FaceBookUser.
userName is only Mandatory parameter to build FaceBookUser
FaceBookUserBuilder builds FaceBookUser by setting optional parameters : UserBasicInfo and ContactInfo
This example illustrates three different FaceBookUsers with different attributes, built from Builder.
fbUser1 was built as FaceBookUser with userName attribute only
fbUser2 was built as FaceBookUser with userName and UserBasicInfo
fbUser3 was built as FaceBookUser with userName,UserBasicInfo and ContactInfo
In this example, composition has been used instead of duplicating all attributes of FaceBookUser in Builder class.
EDIT:
Group all related attributes into logical classes. Define all these classes in FaceBookUser. Instead of adding all these member variables again in Builder, contain FaceBookUser in Builder class.
For simplicity, I have added two classes: UserBasicInfo and ContactInfo . Now explode this FaceBookUser class with other attributes like
NewsFeed
Messages
Friends
Albums
Events
Games
Pages
Ads
etc.
If you duplicate all these attributes in both Builder and FaceBookUser, code will become difficult to manage. Instead, by using composition of FaceBookUser in FaceBookUserBuilder itself, you can simply construction process.
Once you add above attributes, you will build FaceBookUser in step-by-step process as usual.
It will be like this:
FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).
setNewsFeed(newsFeed).
setMessages(messages).
setFriends(friends).
setAlbums(albums).
setEvents(events).
setGames(games).
setAds(ads).build();
You can sure change the fields of your Builder class to be private - then you just need a (public) getter method for each "property" on the builder; and the constructor in Foo calls those methods; instead of just fetching the fields in the Builder object.
Then you can just move your Builder class out of Foo. Simple and straightforward.
But keep in mind: in the end, Builder and Foo are very closely related. They share a common set of fields by design. So any change to Foo affects Builder; and vice versa. Thus it makes a lot of sense to keep them "close together". Maybe not as inner/outer class, but maybe still within the same source file! But then ... only one of them can be public. Is that really what you want?!
In other words: don't rip things apart just "because you can". Only do it if you have good reasons to do so, and if the thing that comes out of that is better than your current solution!
Edit: your problem might not be separation of Foo and Builder, but the fact that your Foo class has too many fields in the first place. Dont forget about the single responsibility principle ... when your class needs more than 5, 6 fields ... it is probably doing too much and should be further sliced! Keep in mind: good OO design is first of all about behavior; not about having 10, 20 fields within some object!
It's difficult to strictly define "The Builder Pattern™", and there are several degrees of freedom regarding the design choices. Some concepts can easily be mixed or abused, and beyond that, it is generally hard (and nearly always wrong) to say "you always have to do it exactly like that".
The question is what should be achieved by applying a "pattern". In your question and the example, you already mixed two concepts, namely the builder pattern and the fluent interface. Playing devil's advocate, one could even sneakily argue that the "Builder" in your case is just the Parameter Object that Thomas already mentioned, which is constructed in a special way (fluently) and enriched with some tricky combination of public and private visibilities.
Some of the possible goals of the builder pattern are overlapping or go hand in hand. But you should ask yourself what the primary goal is in your case:
Should the resulting object be immutable?
Should it be really immutable, with only final final fields, or could there also be setters that just should not be public? (The builder could still call these non-public setters!)
Is the goal to limit visibility in general?
Should there be polymorphic instantiation?
Is the main goal to summarize a large number of constructor parameters?
Is the main goal to offer an easy configuration with a fluent interface, and to manage "default" values?
...
As all these question will have an effect on the subtle differences in the design. However, regarding your actual, high level, "syntactic" question:
You could design the builder as a public static inner class (what you did in the example).
public class Person {
...
public static PersonBuilder create() { ... }
public static class PersonBuilder {
...
public Person build() { ... }
}
}
This offers the strictest form of privacy: The constructors of Person and PersonBuilder may both be private.
You could also place the actual class and its builder in separate files:
public class Person {
...
}
and
public class PersonBuilder {
...
}
A reasonable degree of privacy can be achieved here: The constructors of both can be package private (i.e. have default visibility).
In both cases, the actual usage for clients would be the same, except for the name of the builder class (package.Person.PersonBuilder vs. package.PersonBuilder). The "contents" of the classes would also be the same (except for slightly different visibilities). And in both cases, you can create subclasses of Person, if desired, depending on the builder configuration, and the builder itself can have a fluent interface.
As an alternative to the builder pattern, you could also use a parameter object:
class FooParams {
public int size;
public Color color;
public String name;
}
You can use getters and setters here, instead of public fields, if you prefer.
Then the Foo constructor takes one of these as an argument:
public Foo(FooParams params) {
this.size = params.size;
this.color = params.color;
this.name = params.name;
}
I'm re-writing some code, and I've decided the way to recreate the class, as there are a fixed number of sheets, I'm creating them as enums. This is a decision based on the readability of a builder patter vs a telescoping constructor.
The code I'm grabs some some .xls files, adds headers (and reads some from other .xls files) and perhaps some sub-sheets. It then merges a variety of these sheets together in a specific way to make tabs on a main excel workbook. My issue is that some of the workbook tabs take different numbers of sheets are arguments. I'm trying to apply the builder pattern. This is the sort of code I'm trying to write:
public enum workBookSheet {
mySheet1("Name1","mainSheet1.xls",true,1).addSubSheet("pathToSubSheet1.xls"),
mySheet2("Name2","mainSheet2.xls",true,2).addHeaderSheet("pathToHeaders.xls").addSubsheet("pathtoSubSheet2.xls");
private String tabName;
private String mainSheetName;
private Boolean available;
private Integer order;
private String subSheetName;
private String headerSheetName;
private workBookSheet(String tabName, String mainSheetName, Boolean available, Integer order){
this.tabName = tabName;
this.mainSheetName = mainSheetName;
this.available = available;
this.order = order;
}
public workBookSheet addSubSheet(String subSheetName){
this.subSheetName = subSheetName;
return this;
}
public workBookSheet addHeaderSheet(String headerSheetName){
this.headerSheetName = headerSheetName;
return this;
}
}
The error that java is giving me seems to be saying that Java expects my enum declaration (comma delimited list of 'enum constructors' at the top) to only have the constructor in it, and not additional methods. I can move those methods to a 'builder' method below, without complaint.
public void buildSheets(){
mySheet1.addSubSheet("pathToSubSheet1.xls");
mySheet2.addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls");
}
Is this the only way to implement a builder pattern on an enum? It does require me to run a separate method, which isn't too much hassle. IT does feel like I'm breaking the pattern though (I guess, not such a bad thing if this works.)
N.B I've had a good look around to see if anyone else has asked this question, on SO or elsewhere on the web. The closest I found was a question here on Enums and Factories, but that doesn't quite answer my question. Also I'm aware this isn't quite the builder pattern, as I don't have a separate class that then accepts a build() method that creates a new enum. I guess this is the root of the problem in my initial design, but I am relatively new to Java.
So Is there a better way to use a builder pattern on a Java enum? Or is what I have 'close enough'?
Although it doesn't strictly conform to the builder pattern, the short answer is yes. Sort of.
The missing piece is not being able to call .build() to instantiate the enum constant, because build() can't use new. But you can get quite a few of the benefits of the builder pattern. And let's face it, you can't use static factory methods, and inline subclassing of enum constants is weird.
Here's an example using a Country enumeration.
package app;
import org.apache.commons.lang.StringUtils;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.Set;
import static app.Language.*;
import static com.google.common.base.Preconditions.*;
enum Language {
ITALIAN,
ENGLISH,
MALTESE
}
public enum Country {
ITALY(new Builder(1, "Italy").addLanguage(ITALIAN)),
MALTA(new Builder(2, "Malta").addLanguages(MALTESE, ENGLISH, ITALIAN).setPopulation(450_000));
final private int id;
final private String name;
final private Integer population;
final private Set<Language> languages;
private static class Builder {
private int id;
private String name;
private Integer population;
private Set<Language> languages = EnumSet.noneOf(Language.class);
public Builder(int id, String name) {
checkArgument(!StringUtils.isBlank(name));
this.id = id;
this.name = name;
}
public Builder setPopulation(int population) {
checkArgument(population > 0);
this.population = population;
return this;
}
public Builder addLanguage(Language language) {
checkNotNull(language);
this.languages.add(language);
return this;
}
public Builder addLanguages(Language... language) {
checkNotNull(language);
this.languages.addAll(languages);
return this;
}
}
private Country(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.population = builder.population;
this.languages = builder.languages;
checkState(!this.languages.isEmpty());
}
public int getId() {
return id;
}
public String getName() {
return name;
}
#Nullable
public Integer getPopulation() {
return population;
}
public Set<Language> getLanguages() {
return languages;
}
}
You can even put static factory methods in the builder if you have common ways to build a constant.
So it's not quite Bloch's builder, but it's pretty close.
You can use instance blocks (often incorrectly called "double brace initializers") to customise construction with arbitrary code:
public enum workBookSheet {
mySheet1("Name1", "mainSheet1.xls", true, 1) {{
addSubSheet("pathToSubSheet1.xls");
}},
mySheet2("Name2", "mainSheet2.xls", true, 2) {{
// you can use the fluent interface:
addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls");
// but I would prefer coding separate statements:
addHeaderSheet("pathToHeaders.xls");
addSubSheet("pathtoSubSheet2.xls");
}};
// rest of your class the same...
}
Employing this syntax allows you to work around the limitations imposed by an enum but still have the brevity, convenience and flexibility of a builder/fluent pattern.
mySheet1, mySheet2, etc. are enum constants which follows the JLS syntax defined in section 8.9.1
EnumConstant:
Annotationsopt Identifier Argumentsopt ClassBodyopt
So, you can follow the enum constant by an argument list (the parameters to pass to the constructor) but you can't call a method on the enum constant while declaring it. At most you can add a class body for it.
Beside this, your usage of builder pattern to build enum instances is questionable as in general the builder pattern is used when you have a large number of instances (combinations of field values) in contrast with the concept of enums used for a few instances.
I am learning about the builder pattern, and so far I understood that, it is a great alternative to the commonly patterns used for initialization:
Telescoping Constructor Pattern
JavaBean Pattern
The thing is, I don't really like to remove the getters and setters from the objects in my domain model. I always like to keep them as POJOs. One of the reasons I don't like it is:
If i don't use POJOs, then it is not easy to annotate the variables when using ORM frameworks...
So here are my doubts:
-Is it possible to implement the builder pattern without using static inner classes?
-If I have to use the builder pattern by using the inner class, do you think it is correct to keep the getters and the setters?
-I did a little example for practice where I tried to avoid the inner class.
Could you let me what do you think about it?
Product
public class Product
{
private String color;
private int price;
public Product() {
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String toString() {
return getColor() + "\n" + getPrice();
}
}
Builder
public class Builder
{
private Product product;
public Builder() {
product = new Product();
}
public Builder withColor(String color) {
product.setColor(color);
return this;
}
public Builder withPrice(int price) {
product.setPrice(price);
return this;
}
public Product build() {
return product;
}
}**
Client
public class Client
{
public static void main(String[] args) {
System.out.println(new Builder().withColor("Black").withPrice(11).build());
System.out.println("-----------------------------------------------------");
System.out.println(new Builder().withColor("Blue").withPrice(12).build());
}
}
The Builder pattern is useful to create immutable objects and avoid several constructors with optional parameters.
IMO using Builder pattern to build a POJO which can be updated using setters is useless. You only create an additional class.
Depending on the ORM framework used, it might not need the presence of setter method. But only assigning members values through reflection.
Product class:
public final class Product {
private final String color;
private final int price;
public Product(Builder builder) {
this.color = builder.getColor();
this.price = builder.getPrice();
}
public String getColor() {
return color;
}
public int getPrice() {
return price;
}
public String toString() {
return getColor() + "\n" + getPrice();
}
}
Builder class:
public final class Builder {
private String color;
private int price;
public Builder() {
// Assign any default values
}
public Builder color(String color) {
this.color = color;
return this;
}
public Builder price(int price) {
this.price = price;
return this;
}
protected String getColor() {
return color;
}
protected int getPrice() {
return price;
}
public Product build() {
return new Product(this);
}
}
The builder pattern is most useful in the context of immutable objects. Immutable objects don't have setters by definition. So all of their properties have to be squeezed into the constructor. This is where the builder pattern comes in handy. It allows you to split the initialization of a complex immutable object into multiple, self-explaining instructions so you don't need to have constructor calls like this fictional example all over you code where you can't tell which argument does what:
Thing foo = new Thing(1, 125, Thing.SOMETHING, new Whatchamacallit(17, 676), getStuffManager(StuffManager.ZOMG), true, false, false, maybe);
I don't find that the Builder pattern creates any signficant value when the created object is mutable. Everything you do through the builder can also be done with the created object directly.
Also, I think that your program above is not a textbook example of the builder pattern. You usually don't create an object by passing the builder to the constructor. You create an object by calling a create method on the builder which then passes all its properties to the constructor of the object. This pattern has the advantage that it gives the builder the opportunity to check its internal state for consistency and maybe throw an exception before starting to build the object.
The java StringBuilder class is a good example (the create method being tostring in this case).
What does using a builder here actually gain you?
Nothing as far as I can see: you could just create a new Product and use the getters and setters on it directly. If you have a simple POJO then there is absolutely nothing wrong with:
Product p=new Product();
p.setColour("Black");
p.setPrice(11);
doSomethingWith(p);
Saving a few characters of typing is IMHO not worth introducing a new class / builder abstraction.
Builders are more useful in situations like the following:
You want to create an immutable object (and hence can't use setters)
If you have complicated factory logic that cannot easily be expressed with simple getters and setters or that you want to re-use in different ways
(Occasionally) when you want to have different parts of the code base configure different aspects of the builder for some reason.
The builder pattern lends itself well to producing immutable classes, but it can still be a good option for mutable classes too.
A builder is a reasonable design choice in any situation where an object contains many fields that need to be set during construction; particularly if sensible defaults can be chosen for several of the values.
Whether you use an inner class depends upon your goals. If you wish to force construction through the builder, you can define the builder as an inner class and ensure the outer class only has a private constructor.
Here are Builder collaborations from GoF book:
Collaborations
1. The client creates the Director object and configures it with the desired Builder object.
2. Director notifies the builder whenever a part of the product should be built.
3. Builder handles requests from the director and adds parts to the product.
3. The client retrieves the product from the builder.
The Builder pattern focuses on constructing a complex object step by step. Builder returns the product as a final step. The returned class in absence of the setters may be as good as immutable. With setters, it can be modified. And inner classes help mask the details.
Another point worth noting is that a major motivation behind creational design patterns is that the client doesn't worry about creating the product. The object creation process is delegated to factory, builder, etc. The client doesn't have to worry about object creation. It will specify what it wants and will get it as a result of delegated creation process.
Is it possible to implement the builder pattern without using static
inner classes?
Absolutely, yes. As far as the Builder design pattern is concerned, it does not make any difference if the Builder is an inner class or not.
-If I have to use the builder pattern by using the inner class, do you think it is correct to keep the getters and the setters?
Yes, it is ok. it is kind of like, build the object using a certain template and then customize it, if needed.
-I did a little example for practice where I tried to avoid the inner
class. Could you let me what do you think about it?
Two problems -
the example does not justify the usage of Builder pattern. Builder pattern is used to build a complex object. So if you can simply build product as :
Product p = new Product();
p.setColor(c);
p.setPrice(prc);
Then there is hardly any benefit in the way you have shown.
Product should not have a dependency on Builder.
I found myself thinking if getters are any good in a builder. A builder shouldn't generally be used as a return value - a single method or class should be responsible for creation of the entity using builder. Thus, the method (or class) should keep the information it needs instead of getting it back.
For those reasons, I decided not to use any getters in the builder class. Builder only has setters (be it withAbc(...), setAbc(...) or abc(...)), build() and possibly some private methods like validate().
Using class Product, a sample entity looks like this:
class Product {
private final String color;
private final int price;
private Product(ProductBuilder builder) {
this.color = builder.color;
this.price = builder.price;
}
// equals, hashCode, toString
public builder() {
return new ProductBuilder(this);
}
public static emptyBuilder() {
return new ProductBuilder();
}
public String getColor() {
return color;
}
public int getPrice() {
return price;
}
Now, a builder class is an inner class of the entity, which allows me to use private constructors.
public static class ProductBuilder {
private String color;
private int price;
private ProductBuilder() {
}
private ProductBuilder(Product entity) {
this.color = entity.color;
this.price = entity.price;
}
public ProductBuilder withColor(String color) {
this.color = color;
return this;
}
public ProductBuilder withPrice(int price) {
this.price = price;
return this;
}
public Product build() {
return new Product(this.validate());
}
private ProductBuilder validate() {
if (color == null) {
throw new IllegalStateException("color is null");
}
return this;
}
}
As you can see, I added method builder() to get builder as a copy of the instance and emptyBuilder() as a factory method to hide constructor (maybe there is a better name for it).
Also, when constructing an immutable class, make sure everything inside is immutable as well. Collections are tricky, you have to make a copy, then use Collections.unmodifiable*(...) on it to ensure nobody has a reference to the collection lying under the unmodifiable wrapper.
EDIT: Allegedly, you need getters if you have abstract superclass. That is an overstatement. You only need it if you have a constructor with all params. If you pass the builder instead, like me, you get:
class Product extends Something { ...
private Product(ProductBuilder builder) {
super(builder); // that one must be protected, not private
...
}
public static class ProductBuilder extends SomethingBuilder { ...
protected ProductBuilder validate() {
super.validate();
...
}
}
}
So, do we need getters? This time, not really. We're still fine without them. Some other ideas?
Builder is about several things and you may want to utilize only one aspect: fluent API. You may attain the best fit for your needs by just changing your setters to return this instead of void. Then you can use the chained-setter idiom: return new MyBean().setCheese(cheese).setBacon(bacon);
On a side note, the term "POJO" does not mean the same as "JavaBean". In fact, sometimes these two terms are used as opposites. The point of a POJO is that it doesn't conform to anything else than being a Java object. It may use public variables, for example.