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

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

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

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

  • Building a Rust Command Line Interface to Chat With Llama 3.2
  • Enabling Behavior-Driven Service Discovery: A Lightweight Approach to Augment Java Factory Design Pattern
  • A Beginner’s Guide to GraphQL Interfaces and Unions
  • Contexts in Go: A Comprehensive Guide

Trending

  • Emerging Data Architectures: The Future of Data Management
  • Failure Handling Mechanisms in Microservices and Their Importance
  • Doris: Unifying SQL Dialects for a Seamless Data Query Ecosystem
  • *You* Can Shape Trend Reports: Join DZone's Software Supply Chain Security Research

Factories, Builders and Fluent Interfaces

By 
Aslam Khan user avatar
Aslam Khan
·
Aug. 18, 08 · News
Likes (4)
Comment
Save
Tweet
Share
56.9K Views

Join the DZone community and get the full member experience.

Join For Free

Last week I started working on very short proof of concept with a team that I am currently coaching at a short term insurance company. We hit a very common design decision: when do we use a factory pattern and when do we use a builder pattern.

In the problem at hand, we needed to describe an item that will appear in an insurance policy that must be covered for fire damage. It turns out that these items are not trivial in their structure, and many things influence the premium that will paid by the policy holder for fire insurance. So, the first bit of code (in Java) in the test looked something like this.

FireItem fireItem = new FireItem();
fireItem.setIndustry("Building Construction");
fireItem.setOccupationCode("Workshop");
// the postal/zip code for the location of the insured item
fireItem.setAreaCode(7800);
// ignore the number, we actually created a Money class
fireItem.setSumInsured(200000.00);
fireItem.setRoofing("Non-Standard");

After the test passed, we refactored and I sneaked in a factory method which will be used to honor default values and at the same time threw in a fluent interface (the term coined by Eric Evans and Martin Fowler. After all, I was also quietly introducing Domain Driven Design without actually saying that).

The code looked like this.

FireItem fireItem = FireItem.create()
.inIndustry("Building Construction")
.withOccupation("Workshop")
.InAreaWithPostalCode(7800)
.forSumInsured(200000.00)
.havingRoofing("Non-Standard");

The FireItem class looked like this:

public class FireItem {
String industry;
String occupation;
// other properties ...

private FireItem() { }
public static FireItem create() {
return new FireItem();
}
public FireItem inIndustry(String industry) {
this.industry = industry;
return this;
}
// other chained methods follow a similar style returning "this" ...
}

Nice! Much more readable. But, we then realised that it’s easy for someone to miss one of the methods in the chain. That will result in the item having an incomplete structure. Not good!

One of the things I tend to do as a coach, is to let the team I am working with, experience the problem, solution and any rewards and smells as well. Sometimes I even throw in red herring for sake of experience ;-). So, the third pass at refactoring was to introduce a validate() method on the item which throws an exception if everything was not in place.

try {
FireItem fireItem = FireItem.create()
.inIndustry("Building Construction")
.withOccupation("Workshop")
.InAreaWithPostalCode(7800)
.forSumInsured(200000.00)
.havingRoofing("Non-Standard")
.validate();
} catch (FireItemException e) {
// handle the exception
}

Now the user of this class needs to know that the validate() method must be called before they really want to use an item object. Yuck, that’s smelly! So, for the fourth design refactoring, I introduced a builder and moved the fluent interface to the builder, still using method chaining but introduced a build() method that did the work of the previous validate() method before returning the well structured item. The FireItem class now needs the traditional bunch of getters and setters (rant - the framework goodies need them anyway!!)


import static insurance.FireItemBuilder.fireItem;
// ...
try {
FireItem fireItem = fireItem().inIndustry("Building Construction")
.withOccupation("Workshop")
.InAreaWithPostalCode(7800)
.forSumInsured(200000)
.havingRoofing("Non-Standard")
.build();
} catch (FireItemException e) {
// handle the exception
}

Much better! Note the use of the static import which gives us the liberty to use the static method without specifying the class in code body. The FireItemBuilder class looked like this.

public class FireItemBuilder {
private final FireItem fireItem;
private FireItemBuilder() {
fireItem = new FireItem();
}
public static FireItemBuilder fireItem() {
return new FireItemBuilder();
}
public FireItemBuilder inIndustry(String industry) {
fireItem.setIndustry(industry);
return this;
}
// other chained methods follow a similar style returning "this" ...
public FireItem build() throws FireItemBuilderException {
validate();
return fireItem;
}
private void validate() throws FireItemBuilderException {
// do all validations on the fire item itself and throw an exception if something fails
}
}

Sure, we can improve the bubbling of the exception from validate() to build() and we could do with a better name for validate(). And perhaps, validate() should be on the FireItem class. But let’s stick to factories and builders and fluent interfaces. I think these three things work nicely “together”, when used for the right purpose.

In a nutshell, factories are great for creating objects where defaults and invariants are easily honored during the simple message to the factory. However, if the structure of the object is more complex which makes long argument liss in messages ugly, and some form of validation is necessary before we can use an object; then a builder works beautifully.

An alternative is to allow the object to have an invalid structure but you track it with an invalid state, perhaps using a state pattern. This is not exactly what the state pattern was meant for, but it will work nonetheless.

Also, note that the fluent interface was used to improve readability and kick off a tiny little DSL for describing insurance items. Yes, I know it's Java and that's it's not the best language for creating internal DSL's but the point is that you can maximize the use of your language to create a DSL. After all, DSL's are not about syntactic sugar alone.

Factory (object-oriented programming) Interface (computing) Fluent interface

Published at DZone with permission of Aslam Khan. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building a Rust Command Line Interface to Chat With Llama 3.2
  • Enabling Behavior-Driven Service Discovery: A Lightweight Approach to Augment Java Factory Design Pattern
  • A Beginner’s Guide to GraphQL Interfaces and Unions
  • Contexts in Go: A Comprehensive Guide

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!