模板方法(Template Method)模式

模板方法(Template Method)模式定义:

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 .

定义一个操作中的一个算法框架,把一些步骤推迟到子类去实现。模板方法模式让子类不需要改变算法结构而重新定义特定的算法步骤。

也就是说:模板方法模式定义了一系列算法步骤,子类可以去实现或覆盖其中某些步骤,但不能改变这些步骤的执行顺序。

下面的代码是模板方法模式的示例代码,类HappyPeople的方法celebrateSpringFestival()是一个模板方法,有3个步骤,其中方法travel()是抽象部分,用于子类实现不同客户化逻辑。

package pattern.part1.chapter2.template;

/**
 * Date: 2009-11-18
 * Time: 0:42:25
 */
public class HappyPeopleTestDrive {
    public static void main(String[] args) {
        HappyPeople passengerByAir = new PassengerByAir();
        HappyPeople passengerByCoach = new PassengerByCoach();
        HappyPeople passengerByTrain = new PassengerByTrain();

        System.out.println("Let's Go Home For A Grand Family Reunion...\n");

        System.out.println("Tom is going home:");
        passengerByAir.celebrateSpringFestival();

        System.out.println("\nRoss is going home:");
        passengerByCoach.celebrateSpringFestival();

        System.out.println("\nCatherine is going home:");
        passengerByTrain.celebrateSpringFestival();
    }
}

package pattern.part1.chapter2.template;


public abstract class HappyPeople {
    public void celebrateSpringFestival() {
        subscribeTicket();
        travel();
        celebrate();
    }

    protected final void subscribeTicket() {
        //Buying ticket...
        System.out.println("Buying ticket...");
    }

    protected abstract void travel();

    protected final void celebrate() {
        //Celebrating Chinese New Year...
        System.out.println("Happy Chinese New Year!");
    }
}

package pattern.part1.chapter2.template;

/**
 * Date: 2009-11-18
 * Time: 0:23:43
 */
public class PassengerByAir extends HappyPeople {
    @Override
    protected void travel() {
        //Traveling by Air...
        System.out.println("Travelling by Air...");
    }
}

package pattern.part1.chapter2.template;

/**
 * Date: 2009-11-18
 * Time: 0:22:16
 */
public class PassengerByCoach extends HappyPeople {
    @Override
    protected void travel() {
        //Travel by Coach...
        System.out.println("Travelling by Coach...");
    }
}

package pattern.part1.chapter2.template;

/**
 * Date: 2009-11-18
 * Time: 0:20:05
 */
public class PassengerByTrain extends HappyPeople {
    @Override
    protected void travel() {
        //Travel by Train...
        System.out.println("Travelling by Train...");
    }
}

模版方法模式可以解决某些场景中的代码冗余问题,但也可能引入类的泛滥问题。使用回调可以避免类的泛滥。

回调表示一段可执行逻辑的引用(或者指针),我们把该引用(或者指针)传递到另外一段逻辑(方法)里供这段逻辑适时调用。

比如针对以下需求:查询数据库的记录。

1.得到数据库连接Connection对象;

2.创建Statement对象并执行相关的查询语句;

3.处理查询出来的结果,并在整个执行过程中处理异常。

整个过程中发生变化的主要是第3步,适合用模板模式来处理这个问题,但由于各种各样的查询太多,导致我们需要创建很多的子类来处理这些查询结果,会引起子类的泛滥。因此,我们可以使用回调(Callback)来解决这个问题。

package com.chapter2.callback;
import static org.junit.Assert.assertEquals;

import java.sql.ResultSet;

import org.junit.Test;
public class TemplateTestDrive {
	@Test
	public void testTemplate(){
		boolean called = new SimpleJDBCTemplate()
		.query("Select * from DB", 
				new ResultSetHandler<Boolean>(){
					@Override
					public Boolean handle(ResultSet rs) {
						return true;
					}
			});
		assertEquals(true,called);
	}

}

package com.chapter2.callback;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SimpleJDBCTemplate {
	public <T> T query(String queryString,ResultSetHandler<T> rsHandler){
		Connection connection = null;
		PreparedStatement statement=null;
		ResultSet rs=null;
		try {
			connection = ConnectionUtils.getConnection();
			statement = connection.prepareStatement(queryString);
			rs = statement.executeQuery();
			return rsHandler.handle(rs);
		} catch (SQLException ex) {
			closeStatement(statement);
			statement=null;
			releaseConnection(connection);
			connection=null;
			throw new RuntimeException("a sql exception occured",ex);
		}finally{
			closeStatement(statement);
			releaseConnection(connection);
		}
		
	}
	
	private void releaseConnection(Connection conn){
		if(conn!=null){
			try {
				conn.close();//close the connection or put it back  to the connection pool
			} catch (SQLException e) {
				//todo handle SQLException
			} catch (Throwable ex) {
                //todo handle other exception
            }
		}
	}
	
	private void closeStatement(PreparedStatement statement){
		if(statement!=null){
			try {
				statement.close();
			} catch (SQLException e) {
				//todo handle SQLException
			} catch (Throwable ex) {
                //todo handle other exception
            }
		}
	}
}

package com.chapter2.callback;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class ConnectionUtils {
	public static Connection getConnection(){
		Connection connection = createMock(Connection.class);
		PreparedStatement statement = createMock(PreparedStatement.class);
		try {
			expect(connection.prepareStatement((String)anyObject())).andReturn(statement);
			expect(statement.executeQuery()).andReturn(null);
			replay(connection);
			replay(statement);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return connection;
	}

}
package com.chapter2.callback;

import java.sql.ResultSet;

public interface ResultSetHandler<T> {
	public T handle(ResultSet rs);
}

注:本文大部分内容点来自刘济华的《漫谈设计模式》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值