How to apply template method design pattern in Java

2 minute read

dist files

Photo by Domenico Loia on Unsplash

This week I was with a co-worker doing pair programming and we saw that two Java classes were very similar.

The problem: duplicate code

The two Java classes instantiated a publisher and sent a message to a Kafka topic. The only difference between the two was that they posted on different topics. Here you can see the TestAssignmentPublisher class.

public class TestAssignmentPublisher {

    private static final Logger LOGGER = Logger.getLogger(EventPublisher.class);

    @MessagePublisher(topic = TEST_ASSIGNMENT_TOPIC)
    private Publisher<DomainEvent> publisher;
    
    ...

    public <T extends SpecificRecord> void publish(T record) {
        final DomainEvent<T> domainEvent = new DomainEvent<>(record);
        try {
            publisher.publish(domainEvent);
        } catch (final PublishMessageException e) {
            LOGGER.error("Error publishing domain event of type: " + record.getClass() + " : " + record.toString(), e);
        }
    }
}

And the VisitCreatedPublisher class that as you can see is a “copy-paste” of the previous one.

public class VisitCreatedPublisher {

    private static final Logger LOGGER = Logger.getLogger(EventPublisher.class);

    @MessagePublisher(topic = VISIT_CREATED_TOPIC)
    private final Publisher<DomainEvent> publisher;

    ...

    public <T extends SpecificRecord> void publish(T record) {
        final DomainEvent<T> domainEvent = new DomainEvent<>(record);
        try {
            publisher.publish(domainEvent);
        } catch (final PublishMessageException e) {
            LOGGER.error("Error publishing domain event of type: " + record.getClass() + " : " + record.toString(), e);
        }
    }
}

One might think that the name of the topic could be parameterized by passing it as a parameter to the function that published in the kafka queue.

It was not a possible solution because to instantiate the kafka topic as you can see in the previous code you have to use an annotation to define the topic in which we want to publish.

The solution: Use template method design pattern

As the two classes needed the same code, we thought about using an abstract class where we could put the common code and then an abstract method that would be the one that would give us the publisher corresponding to the implementation that interests us.

public abstract class EventPublisher {

    private static final Logger LOGGER = Logger.getLogger(EventPublisher.class);

    public abstract Publisher<DomainEvent> getPublisher();
    public abstract String getTopicName();

    public <T extends SpecificRecord> void publish(T record) {
        final DomainEvent<T> domainEvent = new DomainEvent<>(record);
        try {
            getPublisher().publish(domainEvent);
        } catch (final PublishMessageException e) {
            LOGGER.error("Error publishing domain event of type: " + record.getClass() + " : " + record.toString(), e);
        }
    }
}

Next we see the first implementation of the abstract class.

public class TestAssignmentEventPublisher extends EventPublisher {

    private static final String TEST_ASSIGNMENT_TOPIC = "EXPERIMENTS.TEST_ASSIGNMENT";

    @MessagePublisher(topic = TEST_ASSIGNMENT_TOPIC)
    private Publisher<DomainEvent> publisher;

    @Override
    public Publisher<DomainEvent> getPublisher() {
        return publisher;
    }

    @Override
    public String getTopicName() {
        return TEST_ASSIGNMENT_TOPIC;
    }
}

And here we have the second implementation of the abstract class.

public class VisitCreatedEventPublisher extends EventPublisher {

    private static final String VISIT_CREATED_TOPIC = "VISIT.VISIT";

    @MessagePublisher(topic = VISIT_CREATED_TOPIC)
    private Publisher<DomainEvent> publisher;

    @Override
    public Publisher<DomainEvent> getPublisher() {
        return publisher;
    }
    @Override
    public String getTopicName() {
        return VISIT_CREATED_TOPIC;
    }
}

We are using the design pattern called template where we have a common logic which is what we have put in the abstract class and then for each subclass we define the topic where we want to publish the messages.

we have managed to reuse code and leave it extensible to be able to add future implementations that will be able to publish in other kafka topics without changing the code we already have.

Conclusion

In this post we have seen how to reuse code using the design pattern called template. Do you use design patterns when developing software? What is your favorite?

I won't give your address to anyone else, won't send you any spam, and you can unsubscribe at any time.
Disclaimer: Opinions are my own and not the views of my employer

Updated:

Comments