DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Design Pattern: What You Need to Know to Improve Your Code Effectively
  • Prototype Pattern in JavaScript
  • Object Relational Behavioral Design Patterns in Java
  • Distribution Design Patterns in Java - Data Transfer Object (DTO) And Remote Facade Design Patterns

Trending

  • A Guide to Container Runtimes
  • Solid Testing Strategies for Salesforce Releases
  • Internal Developer Portals: Modern DevOps's Missing Piece
  • Unlocking AI Coding Assistants Part 2: Generating Code
  1. DZone
  2. Coding
  3. Languages
  4. Achieving Immutability with Builder Design Pattern

Achieving Immutability with Builder Design Pattern

Immutable classes define objects which, once created, never change their state.

By 
Shekhar Gulati user avatar
Shekhar Gulati
·
Aug. 03, 10 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
63.5K Views

Join the DZone community and get the full member experience.

Join For Free

One piece of advice from Effective Java is that you should make your classes Immutable unless there is a good reason to make them mutable. If a class cannot be made immutable, limit its mutability as much as possible. Immutable classes define objects which, once created, never change their state. All the state information is provided at the time the object is constructed and it does not change for the lifetime of the object.

Why should we write Immutable classes?

Immutable classes offer many advantages over mutable classes. These are:

  1. An immutable object is simple and easier to use as it can be in only one state, the state in which it was created.
  2. They are inherently thread safe, i.e. they do not require synchronization.
  3. The objects of immutable classes can be shared freely. For example, Boolean class reuses its existing instances TRUE and FALSE and whenever you call Boolean.valueOf method it gives you the already created instances.

Creating an Immutable class

A simple immutable class can be like this:

public final class User {private final String username;private final String password;public User(String username, String password) {this.username = username;this.password = password;}public String getUsername() {return username;}public String getPassword() {return password;}}

 

This class is immutable because:

  1. It does not provide setter methods or mutators.
  2. The Class can't be extended because it is final. This could have also been done by making the constructor private.
  3. Fields of the class are all final and private.

It is important to note that this class was very simple with only two fields.  In most of the classes in our real applications there are more than two fields. Also, most of these fields are not mandatory for object creation. For example, a user in a real application will have a username, password, firstname, lastname, creationDate, emailAddress, etc., but for user creation here, only a username and password are required. So, we design our class as shown below:

public final class User {private final String username;private final String password;private String firstname;private String lastname;private String email;private Date creationDate;public User(String username, String password) {this.username = username;this.password = password;creationDate = new Date();}public String getUsername() {return username;}public String getPassword() {return password;}public String getFirstname() {return firstname;}public void setFirstname(String firstname) {this.firstname = firstname;}public String getLastname() {return lastname;}public void setLastname(String lastname) {this.lastname = lastname;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Date getCreationDate() {return new Date(creationDate.getTime());}}

 

This class is not immutable because it has mutators, i.e. setters. So, instances of this class can be modified after creation.  This approach has the disadvantage that objects can be in an inconsistent state part of the way through their construction and you have to put in extra effort to ensure thread safety.

Builder Design Pattern comes to the Rescue

According to Gof:

The Builder Pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.

The builder design pattern provides a way for you to build complex immutable objects. The process is:

  1. The client calls a constructor (or static factory) with all the required parameters and gets a builder object.
  2. The client calls setter like methods to set each optional parameter of interest.
  3. Finally the client calls the build method to generate the object which is immutable.

Immutable User

public class ImmutableUser {private final String username;private final String password;private final String firstname;private final String lastname;private final String email;private final Date creationDate;private ImmutableUser(UserBuilder builder) {this.username = builder.username;this.password = builder.password;this.creationDate = builder.creationDate;this.firstname = builder.firstname;this.lastname = builder.lastname;this.email = builder.email;}public static class UserBuilder {private final String username;private final String password;private final Date creationDate;private String firstname;private String lastname;private String email;public UserBuilder(String username, String password) {this.username = username;this.password = password;this.creationDate = new Date();}public UserBuilder firstName(String firsname) {this.firstname = firsname;return this;}public UserBuilder lastName(String lastname) {this.lastname = lastname;return this;}public UserBuilder email(String email) {this.email = email;return this;}public ImmutableUser build() {return new ImmutableUser(this);}}public String getUsername() {return username;}public String getPassword() {return password;}public String getFirstname() {return firstname;}public String getLastname() {return lastname;}public String getEmail() {return email;}public Date getCreationDate() {return new Date(creationDate.getTime());}}

 

You should also check the invariants in the build method and throw in an IllegalStateException if any attribute is invalid. This will ensure that the object is in a workable state once it is instantiated.

The client code will look like this :

public static void main(String[] args) {ImmutableUser user = new ImmutableUser.UserBuilder("shekhar","password").firstName("shekhar").lastName("gulati").email("shekhargulati84@gmail.com").build();}

 

In this way you build a complex object which is immutable and has all the advantages of immutable objects.

Note : Effective Java is a must read for every Java developer

Design Object (computer science)

Opinions expressed by DZone contributors are their own.

Related

  • Design Pattern: What You Need to Know to Improve Your Code Effectively
  • Prototype Pattern in JavaScript
  • Object Relational Behavioral Design Patterns in Java
  • Distribution Design Patterns in Java - Data Transfer Object (DTO) And Remote Facade Design Patterns

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!