Gang of Four Behavioural pattern: Template Method
Behavioural Pattern
Defer the exact steps of an algorithm to a subclass. Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
The Template Method Pattern uses an abstract class. The abstract class has a method ( called buildPage() in this example ) which calls the abstract methods in the correct order.
The exact implementation of the abstract methods is left to sub classes of the abstract class.
To get the code for this example:
git clone https://github.com/spotadev/gangoffour.git
In src/main/java navigate to this package:
com.javaspeak.designpatterns.go4.behavioural.templatemethod
You can run the code from the main method of:
TemplateMethodApplication
In this example AbstractHtmlPage is extended by the class HomePage to provide implementation of the abstract methods:
getTitle(),
getHeader(),
getContent(),
getFooter()
package com.javaspeak.designpatterns.go4.behavioural.templatemethod;
/**
* The Template Method Pattern uses an abstract class. The abstract class has a method
* ( called buildPage() in this example ) which calls the abstract methods in the correct order.
* <p>
* The exact implementation of the abstract methods is left to sub classes of the abstract class.
* <p>
* In this example AbstractHtmlPage is extended by the class HomePage to provide implementation of
* the abstract methods, getTitle(), getHeader(), getContent(), getFooter();
*
* @author John Dickerson - 22 Feb 2020
*/
public class TemplateMethodApplication {
private void runExample() throws FormatException {
AbstractHtmlPage htmlPage = new HomePage();
String html = htmlPage.getHtml();
System.out.println( html );
}
public static void main( String[] args ) throws FormatException {
TemplateMethodApplication application = new TemplateMethodApplication();
application.runExample();
}
}
package com.javaspeak.designpatterns.go4.behavioural.templatemethod;
import java.util.LinkedList;
/**
* The Template Method Pattern uses an abstract class. The abstract class has a method
* ( buildPage() ) which calls the abstract methods in the correct order.
* <p>
* The implementation of the abstract methods is left to sub classes of the abstract class.
*
* @author John Dickerson - 22 Feb 2020
*/
public abstract class AbstractHtmlPage {
// abstract methods
public abstract String getTitle();
public abstract String getHeader();
public abstract String getContent();
public abstract String getFooter();
/**
* Parses the xml of the document into a LinkedList
*
* @param html
* html to parse
*
* @return LinkedList
*
* @throws FormatException
* FormatException is thrown if the html is not well formed.
*/
private LinkedList<String> getLinkedList( String html ) throws FormatException {
int start;
int end;
LinkedList<String> elements = new LinkedList<String>();
while ( html.length() != 0 ) {
start = html.indexOf( "<" );
end = html.indexOf( ">" );
if ( start > 0 ) {
elements.add( html.substring( 0, start ) );
}
if ( start != -1 && end == -1 ) {
throw new FormatException( "Found < but cannot find closing >" );
}
if ( start != -1 ) {
elements.add( html.substring( start, end + 1 ) );
if ( html.length() > end ) {
html = html.substring( end + 1 );
}
}
else {
elements.add( html );
html = "";
}
}
return elements;
}
/**
* Build up the String for the tabs
*
* @param level
* the number of tabs
*
* @return
* the String of spaces representing the tabs
*/
private String getTab( int level ) {
StringBuilder sb = new StringBuilder();
for ( int i = 0; i < level; i++ ) {
sb.append( " " );
}
return sb.toString();
}
/**
* This method formats the html with proper space indents
*
* @param html
* The html to format
*
* @return
* formatted html with proper indents
*
* @throws FormatException
* FormatException thrown if html not well formed.
*/
private String formatHtml( String html ) throws FormatException {
String formattedHtml = html.trim();
formattedHtml = formattedHtml.replaceAll( "\n", "" );
formattedHtml = formattedHtml.replaceAll( "\t", "" );
int currentLevel = -1;
LinkedList<String> elements = getLinkedList( formattedHtml );
StringBuilder sb = new StringBuilder();
String element;
for ( int i = 0; i < elements.size(); i++ ) {
element = elements.get( i );
if ( elements.get( i ).startsWith( "<" ) ) {
if ( element.indexOf( "/" ) == -1 ) {
if ( !( i > 0 && elements.get( i - 1 ).startsWith( "</" ) ) ) {
currentLevel++;
}
sb.append( getTab( currentLevel ) );
sb.append( elements.get( i ) );
}
else {
currentLevel--;
sb.append( getTab( currentLevel ) );
sb.append( element );
}
}
else {
currentLevel++;
sb.append( getTab( currentLevel ) );
sb.append( element );
}
sb.append( "\n" );
}
return sb.toString();
}
/**
* This method determines the order which the abstract methods are called
*
* @return
* unformatted html
*/
private String buildPage() {
StringBuffer sb = new StringBuffer( "<html><head><title>" );
sb.append( getTitle() );
sb.append( "</title></head><body>" );
sb.append( "<table width=\"100%\" cellspacing=\"10\" " );
sb.append( "cellpadding=\"10\" ><tr><td>" );
sb.append( getHeader() );
sb.append( "</td></tr><tr><td>" );
sb.append( getTitle() );
sb.append( "</td></tr><tr><td>" );
sb.append( getContent() );
sb.append( "</td></tr><tr><td>" );
sb.append( getFooter() );
sb.append( "</td></tr>" );
sb.append( "</table></body></html>" );
return sb.toString();
}
/**
* Gets the formatted html
*
* @return
* formated html
*
* @throws
* FormatException FormatException is thrown if the html is badly ormed
*/
public String getHtml() throws FormatException {
String html = buildPage();
String formattedHtml = formatHtml( html );
return formattedHtml;
}
}
package com.javaspeak.designpatterns.go4.behavioural.templatemethod;
/**
* In the Template Method pattern a class such as this one extends the abstract class and provides
* implementation for the abstract methods. In the the abstract class it is extending there is a
* method ( buildPage() ) which calls the abstract methods in the correct order.
*
* @author John Dickerson - 22 Feb 2020
*/
public class HomePage extends AbstractHtmlPage {
@Override
public String getTitle() {
return "My Home Page";
}
@Override
public String getHeader() {
return "<a href=\"www.google.com\">Google</a>";
}
@Override
public String getContent() {
return "All knowledge can be had from google";
}
@Override
public String getFooter() {
return "Design Production";
}
}
package com.javaspeak.designpatterns.go4.behavioural.templatemethod;
/**
* This exception is thrown if html is not well formed.
*
* @author John Dickerson - 22 Feb 2020
*/
public class FormatException extends Exception {
private static final long serialVersionUID = -5550364727379819980L;
public FormatException() {
}
public FormatException( String message ) {
super( message );
}
public FormatException( Throwable cause ) {
super( cause );
}
public FormatException( String message, Throwable cause ) {
super( message, cause );
}
public FormatException( String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace ) {
super( message, cause, enableSuppression, writableStackTrace );
}
}
Back: Gang of Four
Page Author: JD