{{announcement.body}}
{{announcement.title}}

Design Patterns Demystified - Template Design Pattern

DZone 's Guide to

Design Patterns Demystified - Template Design Pattern

In the first article of this series, we take a look at demystifying the Template design pattern by exploring the why, what, how, and where.

· Web Dev Zone ·
Free Resource

Welcome to the Design Patterns Demystified (DPD) series, in this edition we are going to discuss Template Design Pattern. So let us understand the why, how, what, and where of Template Design Pattern.

The Why

Let us understand first, why we need this pattern with the help of an example. Let's you are building a reusable library which is orchestrating the operation of buying an item on an e-commerce platformNow, irrespective of what you are buying, you will follow the same sequence of steps like building your cart, adding an address, filling in payment details, and then finishing the payment. The details in these steps will vary based on what you are buying, how much you are buying, the delivery address, and the preferred mode of payment, but the complete orchestration of steps remains the same.

Now, imagine you are given the responsibility of building a re-usable library that is supposed to be used by many different e-commerce platforms to enable purchase of products on their platform. Here, each e-commerce platform will have different flows and requirements in terms of all the factors described above, but eventually, all of them want to follow the same sequence of steps. So how do you ensure that your library remains open for limited extension but closed for modification of the overall behavior and at the same time, every platform also respects the contract provided by the library? The answer is, Template Design pattern.

The What

Let us understand what template design is. In template design, we create an abstraction/specification which specifies the overall behavior (and we make sure that this overall behavior is immutable) and we declare the inner steps of the overall behaviors but don't provide details of the inner steps, because, if you recall, every platform/consumer may have their own implementation of these inner steps.

The How

Let us use the same example as described above to show how we can implement this pattern. The example uses Java, but you are free to choose your object-oriented programming language for this.

The first step is to create the EcommercePaymentEngine specification where we provide the orchestration but leave the inner details to the adopters to implement. Here is how it looks:

Java
 




x
22


 
1
public abstract class EcommercePaymentEngine {
2
 
          
3
    abstract void buildCart();
4
 
          
5
    abstract void addAddress();
6
 
          
7
    abstract void addPaymentDetails();
8
 
          
9
    public final void pay(){
10
        try {
11
            buildCart();
12
            addAddress();
13
            addPaymentDetails();
14
        }catch (Exception e){
15
            System.out.println("Something went wrong, error is : " + e);
16
            System.out.println("Also, rollback stuff !!");
17
        }finally{
18
            System.out.println("cleaning up resources");
19
            //close any opened resources
20
        }
21
    }
22
}



Let'ss walk through what is happening here. We have an abstract class called  EcommercePaymentEngine. This has a final method as pay(). This is the orchestrator method. Notice that it is intentionally made final because we don't want any implementer to tamper with the orchestrator. This orchestrator function is wrapping up all the steps which are universal to any e-commerce platform (at least in the utopian world of this post) but those methods are abstract. It is up to the e-commerce platforms to provide details on those behaviors as those behaviors will vary from one platform to another.

Now, let us assume that two e-commerce giants, Foo and Bar, have agreed to use your awesome  EcommercePaymentEngine. The implementation at Foo's end would look like:

Java
 




xxxxxxxxxx
1
16


 
1
public class FooPlatform extends EcommercePaymentEngine {
2
    @Override
3
    void buildCart() {
4
        System.out.println("foo only sells shoes");
5
    }
6
 
          
7
    @Override
8
    void addAddress() {
9
        System.out.println("foo only support country codes in UK");
10
    }
11
 
          
12
    @Override
13
    void addPaymentDetails() {
14
        System.out.println("foo only accepts VISA/MasterCard");
15
    }
16
}


and, expectedly, the implementation at Bar's end would look like:

Java
 




xxxxxxxxxx
1
16


1
public class BarPlatform extends EcommercePaymentEngine {
2
    @Override
3
    void buildCart() {
4
        System.out.println("bar only sells chocolates");
5
    }
6
 
          
7
    @Override
8
    void addAddress() {
9
        System.out.println("bar only support US country codes");
10
    }
11
 
          
12
    @Override
13
    void addPaymentDetails() {
14
        System.out.println("bar only supports paypal !!");
15
    }
16
}



Now Foo and Bar can just invoke the pay method in their platform and that should be it. They will get the complete template implemetnation of EcommercePaymentEngine's pay() method out of the box. Below is a sample implementation of their invocation:

Java
 




xxxxxxxxxx
1
22


1
public class Main {
2
 
          
3
    public static void main(String[] args) {
4
        processPaymentsForFoo();
5
        processPaymentsForBar();
6
    }
7
 
          
8
    private static void processPaymentsForFoo(){
9
        System.out.println("------Foo using the ecommerce payment engine-------");
10
        EcommercePaymentEngine fooPaymentEngine = new FooPlatform();
11
        fooPaymentEngine.pay();
12
        System.out.println("------Foo implementation completed-------\n\n\n");
13
    }
14
 
          
15
    private static void processPaymentsForBar(){
16
        System.out.println("------Bar using the ecommerce payment engine-------");
17
        EcommercePaymentEngine barPaymentEngine = new BarPlatform();
18
        barPaymentEngine.pay();
19
        System.out.println("------Bar implementation completed-------");
20
    }
21
}
22
 
          


This will produce the following output:

Java
 




xxxxxxxxxx
1
15


1
------Foo using the ecommerce payment engine-------
2
foo only sells shoes
3
foo only support country codes in UK
4
foo only accepts VISA/MasterCard
5
cleaning up resources
6
------Foo implementation completed-------
7
 
          
8
 
          
9
 
          
10
------Bar using the ecommerce payment engine-------
11
bar only sells chocolates
12
bar only support US country codes
13
bar only supports paypal !!
14
cleaning up resources
15
------Bar implementation completed-------


The Where

The template design pattern comes handy for collaboration and promotes the whole concept of modularity and re-usability. The other visible benefits of it are code de-duplication, easy version management, etc. If you are working on a large project, there will be plenty of opportunities for implementing this pattern because such large projects tend to have a lot of duplication and overlap of functionalities. Having said that, we should not overuse this pattern; otherwise we will end up in a dependency-mess of tightly coupled templates.

The complete code of this tutorial is available at this link.

Happy Learning!!

Topics:
design patterns for beginners, design patterns in java, design patterns uncovered, template design pattern

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}