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

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Decorating Microservices
  • Decorator Pattern to Solve Integration Scenarios in Existing Systems

Trending

  • AI Agents: A New Era for Integration Professionals
  • Go 1.24+ Native FIPS Support for Easier Compliance
  • SaaS in an Enterprise - An Implementation Roadmap
  • Caching 101: Theory, Algorithms, Tools, and Best Practices

The Decorator Builder

The Decorator Pattern is useful, but the stacking of Decorators can make your code hard to read. Combine the Builder and Decorator patterns for more synergy.

By 
Nehme Bilal user avatar
Nehme Bilal
·
Dec. 20, 16 · Tutorial
Likes (27)
Comment
Save
Tweet
Share
17.1K Views

Join the DZone community and get the full member experience.

Join For Free

In my previous article, Is Inheritance Dead?, I discussed the advantages of using the decorator pattern over inheritance. While most readers agree that the decorator pattern (and composition in general) has many advantages over inheritance, composing decorators came up several times as one of the main pain-points of using the decorator pattern. In this short article, I will present a simple approach to overcome this difficulty.

Composing Decorators

Recall that the decorator pattern is designed in a way that multiple decorators can be stacked on top of each other, each adding a new functionality (see Is Inheritance Dead? for more details). Stacking decorators and choosing their order (referred to as composing decorators) can be difficult to implement and can lead to code that is difficult to read and maintain.

To illustrate, let’s consider the email service example discussed in Is Inheritance Dead? We can create an instance of IEmailService that is thread-safe, implements retries, has a cache and has verbose logging by composing decorators as follows:

IEmailService emailService = new EmailServiceCacheDecorator(
  new EmailServiceLoggingDecorator(new EmailServiceRetryDecorator(
    new EmailServiceLoggingDecorator(new EmailServiceThreadSafetyDecorator(
  new EmailService())))));

As you can see, the resulting code can be a bit overwhelming. In addition, applying decorators in the wrong order can lead to incorrect behavior.

In contrast to a hierarchy issue, such as the exploding class hierarchy issue discussed in my previous post, the difficulty of composing decorators can be easily overcome by organizing the code a little bit differently.

The Decorator Builder

The decorator builder is not a new pattern, it's just a way of using the builder pattern to make composing decorators easier. This is particularly useful for public API's where simplicity is crucial.

The code below illustrates a decorator builder for the email service API discussed in the previous section:

public class EmailServiceBuilder
{
    private IEmailService emailService = new EmailService();

    public EmailServiceBuilder synchronize() {
        emailService = new EmailServiceThreadSafetyDecorator(emailService);
        return this;
    }

    public EmailServiceBuilder retry() {
        emailService = new EmailServiceRetryDecorator(emailService);
        return this;
    }

    public EmailServiceBuilder log() {
        emailService = new EmailServiceLoggingDecorator(emailService);
        return this;
    }

    public EmailServiceBuilder cache() {
        emailService = new EmailServiceCacheDecorator(emailService);
        return this;
    }

    public IEmailService build() {
        IEmailService es = emailService;

        // Reset the builder so it can be reused
        emailService = new EmailService();

        return es;
    }
}


Using this decorator builder, the same instance of IEmailService discussed above can be created as follows:

IEmailService emailService = new EmailServiceBuilder().synchronize()
  .log().retry().log().cache().build();


Notice that the resulting code is easier to read, is verbose and less error prone than the original code. Furthermore, the order in which the decorators are added to the builder is the same as the order in which the decorators will be executed at runtime. In fact, without the builder, the order was inversed, which can cause confusion.

Conclusion

Composing decorators is not really a drawback of the decorator pattern. In fact, like any other Java code, it can be dramatically simplified by organizing the code a little bit differently (e.g. by using more functions and classes). In this article, we used the builder pattern to simplify composing decorators. As shown, the resulting code is simple and easy to maintain.

Decorator pattern

Opinions expressed by DZone contributors are their own.

Related

  • Decorating Microservices
  • Decorator Pattern to Solve Integration Scenarios in Existing Systems

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!