What if we needed to create logs for all user actions on a project? Imagine if we repeated the same code for everything. The log would probably be like:
Header – Always the same
Body – Variable
Bottom – Always the same
Imagine if we implemented these logs without a template (100 log classes implemented separately) and suddenly the client wants to change the log Header and Bottom. We would have to correct all the 100 classes! After correcting all the classes, we would be obligated to test all those logs. Can you imagine how bad it would be?
Fear not! There is a solution for this problem. We can use a powerful Pattern that I really like called Template Method Pattern.
With Template Method, we can encapsulate all these repeated actions and reuse them as much as we want. Now, if something changes on the log Header or the Bottom, even something regarding the creation of the log, we can change it in just one place! Yes, very easy, just in one place! Make your code flexible and powerful and fully master this Pattern!
Get the Design_Patterns_Saga_GitHub_Source_Code
1 – UserActionsLog – This is our Template. We are basically defining the Template for all log generation. You can see that this class is abstract. Also, we implemented the common methods and declared the generateBodyLog() method as abstract because this is the different content from all logs.
In the generateLog() method we orchestrate the invocations from the methods in order to get the log generation encapsulated.
public abstract class UserActionsLog { private String userName; private boolean logCreated; protected UserActionsLog(String userName) { createLogFile(); this.userName = userName; } private void generateHeaderLog() { System.out.println("Log Date:" + new Date()); } public abstract void generateBodyLog(); private void generateBottomLog() { System.out.println("Action executed by:" + userName); } public void generateLog() { generateHeaderLog(); generateBodyLog(); generateBottomLog(); verifyLogFile(); } private void createLogFile() { System.out.println("Creating log file...."); } private void verifyLogFile() { System.out.println("Verifying if the " + "file and log was created."); logCreated = true; } public boolean isLogCreated() { return logCreated; } }
2 – The log implementations: These are the classes we created to pass the user name to the constructor and implement the specific generateBodyLog() method because each log will change only in the body content.
public class CustomerRegisterLog extends UserActionsLog { public CustomerRegisterLog(String userName) { super(userName); } @Override public void generateBodyLog() { System.out.println("Generating Customer body log.."); } } public class CompanyReceiptLog extends UserActionsLog { public CompanyReceiptLog(String userName) { super(userName); } @Override public void generateBodyLog() { System.out.println("Generating Company Receipt body log.."); } }
3 – Unit Tests: It’s done. Now we can execute the tests to check if the log is correct.
public class TemplateMethodTest { private static final String USER_NAME = "Juggy"; @Test public void executeCustomerLogTest() { UserActionsLog customerLog = new CustomerRegisterLog(USER_NAME); customerLog.generateLog(); Assert.assertTrue(customerLog.isLogCreated()); } @Test public void executeCompanyReceiptTest() { UserActionsLog companyReceiptLog = new CompanyReceiptLog(USER_NAME); companyReceiptLog.generateLog(); Assert.assertTrue(companyReceiptLog.isLogCreated()); } }
Summary of actions:
1 – Created the Template Method class.
2 – Declared the Template Method class as abstract.
3 – Implemented the common methods in the Template Method class.
4 – Created the specific method as abstract in the Template Method class.
5 – Created the orchestrator method in the Template Method class.
6 – Created the specific class to implement the specific abstract method.
7 – Instantiated the specific class and invoked the orchestrator method.
To practice the Template Method Pattern you can create another type of Log class, for example, the CompanyCostsLog and create another test method to make sure it works! Try to use TDD (Test Driven Development). Start the development from the test.