Template Method Pattern
Template method pattern defines the skeleton of an algorithm in a method referred to as theTemplate Method
deferring some steps to subclasses. The pattern is mostly used for building application frameworks where the framework implement the invariant pieces of the application's architecture and provide place holders or hooks for client customizations.
Examples from Java API
1. The Comparable
interface defines the compareTo
method which is a template method
2. The java applet class provides init
, start
, stop
, paint
and destroy
hook methods for creating an applet
3. The actionPerformed
method in ActionListener
interface is a template method
4. The doGet
and doPost
methods in abstract class HttpServlet
are examples of template methods
import java.awt.Color; import java.awt.Graphics; import javax.swing.JApplet; /** * * HelloWorldApplet.java */ public class HelloWorldApplet extends JApplet { private String welcomeString = null; public void init() { welcomeString = "Hello World"; } public void paint(Graphics g) { int x = (getParent().getWidth() / 2) - 50; int y = (getParent().getHeight()/ 2) - 50; g.drawString(welcomeString, x, y); } public void start() {} public void stop() {} public void destroy() {} }
There are four types of methods which an abstract class may implement
1. Template. A template method is the one in abstract class that combines concrete, abstract and hook methods together into an algorithm. This method is final and not supposed to change.
2. Concrete. A concrete method is one defined in the abstract class and not implemented by subclasses.
3. Abstract. An abstract method is one declared in the abstract class and implemented by subclasses.
4. Hook. A hook method is declared and defined in the abstract class. Subclasses may implement this method to override the default behaviour.
The below example demonstrates a database transaction abstract class
DBTx
which executes all the queries specified for the transaction or none. The final public void execute()
method is the template method which encompasses the algorithm used for executing the transaction. The method getQueryList
is declared as abstract for subclasses to implement and return behavior specific queries.package patterns.example.template; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.List; /** * * File: DBTx.java */ public abstract class DBTx { private Connection connection = null; protected abstract List<String> getQueryList(); public DBTx(Connection connection) throws SQLException { this.connection = connection; } // template method final public void execute() throws SQLException { beginTxn(); executeQuery(); commit(); endTxn(); } private void beginTxn() throws SQLException { if (connection != null) connection.setAutoCommit(false); } private void executeQuery() { for (String query : getQueryList()) { executeQuery(query); } } private void executeQuery(String query) { Statement stmt = null; try { stmt = connection.createStatement(); stmt.executeUpdate(query); } catch (SQLException e) { System.out.println("Failed to execute query " + query + " Error: " + e.getMessage()); rollback(); } finally { close(stmt); } } private void commit() throws SQLException { if (connection != null) connection.commit(); } private void endTxn() throws SQLException { if (connection != null) connection.setAutoCommit(true); } private void rollback() { try { if (connection != null) connection.rollback(); } catch (SQLException e) { System.out.println("Transaction rollback failed " + e.getMessage()); } } private void close(Statement stmt) { try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { // ignore } } }
package patterns.example.template; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * * File: BalanceUpdater.java */ public class BalanceUpdater extends DBTx { public BalanceUpdater(Connection connection) throws SQLException { super(connection); } @Override protected List<String> getQueryList() { List<String> queryList = new ArrayList<String>(); queryList.add("UPDATE sample.employee SET balance = balance + 10 WHERE emp_id = 1"); queryList.add("UPDATE sample.employee SET balance = balance + 11 WHERE emp_id = 4"); return queryList; } }
package patterns.example.template; /** * * File: DBConfig.java */ public interface DBConfig { String getDriverName(); String getConnectionString(); String getUserName(); String getPassword(); }
package patterns.example.template; /** * * File: MySQLConfig.java */ public class MySQLConfig implements DBConfig { private static final String DB_CONNECTION_STR = "jdbc:mysql://localhost:3306/sample"; private static final String USERNAME = "pankaj"; private static final String PASSWORD = "pankaj"; private static final String DRIVER_NAME = "com.mysql.jdbc.Driver"; @Override public String getDriverName() { return DRIVER_NAME; } @Override public String getConnectionString() { return DB_CONNECTION_STR; } @Override public String getUserName() { return USERNAME; } @Override public String getPassword() { return PASSWORD; } }
The
ConnectionManager
class for managing jdbc connectionspackage patterns.example.template; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * * File: ConnectionManager.java */ public class ConnectionManager { private DBConfig config = null; public ConnectionManager(DBConfig config) { this.config = config; } public Connection getConnection() { try { Class.forName(config.getDriverName()); return DriverManager.getConnection(config.getConnectionString(), config.getUserName(), config.getPassword()); } catch (ClassNotFoundException e) { System.out.println("Unable to register driver for the database " + e.getMessage()); } catch (SQLException e) { System.out.println("Unable to get connection for the database " + e.getMessage()); } return null; } public void closeConnection(Connection connection) { try { connection.close(); } catch (SQLException e) { // ignore } } }
The client program
package patterns.example.template; import java.sql.Connection; import java.sql.SQLException; /** * * File: TemplateExample.java */ public class TemplateExample { private static ConnectionManager conxnMgr = null; private static Connection conxn = null; public static void main(String[] args) { init(); try { DBTx txn = new BalanceUpdater(conxn); txn.execute(); } catch (SQLException e) { System.out.println("Failed to update balance " + e.getMessage()); } clean(); } private static void init() { conxnMgr = new ConnectionManager(new MySQLConfig()); conxn = conxnMgr.getConnection(); } private static void clean() { conxnMgr.closeConnection(conxn); } }
Class Diagram
References:
Avajava
tech.puredanger.com
No comments :
Post a Comment