模板方法模式:在一个方法中定义一个算法的骨架,而将一些算法延迟到子类中去实现,模板方法使得子类在可以不改变
算法结构的时候,自己重新定义算法中的步骤
先把定义给出来,以后再慢慢补充内容 先给一个Hibernate中可以用到的模板方式>>
我们在写Hibernate测试用例的时候或者调用的时候 经常要去获得getCurrentSession()然后控制事务,我们可以定义一个这样的接口:
import org.hibernate.Session;
public interface CrudOperate {
Object doCurd(Session session);
}
//Hibernate方法
public class HibernateUtils {
//final变量必须被初始化
private static final SessionFactory factory;
static {
//因为SessionFactory是重量级的 所以创建很耗时 争对每一个应用的每一个数据库应该用单例保证只有一个实例
//new Configuration().configure()默认读取hibernate.cfg.xml文件
try{
factory = new Configuration().configure().buildSessionFactory();
}catch(Throwable ex) {
System.out.println("Initial SessionFactory failed!" + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return factory;
}
public static Session getSession() {
return factory.getCurrentSession();
}
}
定义一个模板方法>>
public class TestFrame {
public Object execute(CrudOperate crud){
Session session = HibernateUtils.getSession();
Object result = null;
session.beginTransaction();
try{
result = crud.doCurd(session);
session.getTransaction().commit();
}catch (Throwable e) {
session.getTransaction().rollback();
throw new RuntimeException(e);
}//因为获得的session是currentSession会自动关闭就不需要自己手动控制去关闭了
return result;
}
}
我们在测试的时候就只要 在自己的方法里面去实现 就行了 如:
private static final TestFrame frame = new TestFrame();
@Test
public void test() {
frame.execute(new CrudOperate() {
public Object doCurd(Session session) {
//在这里去处理我们具体的查询操作
}
});
}
这里就封装好了,采用的是接口回调的方式。。。其实Spring中提供了更多的模板方法,可以去看看,我看了眼 没怎么看懂。。。
有了上面这个用例,我们可以看到 所谓的模板 其实就是一个方法,这个方法将算法定义成一组步骤,每一个步骤都是可以去抽象,由子类来负责实现,可以确保算法的结构不变,而子类有可以提供部分实现。上面举的例子采用了回调的方法 如果第一次看还比较难看,举个比较简单的例子:
abstract class AbstractClass{
//定义了算法的结构 final型的就是防止子类去更改算法的接口
final void tempalteMethod() {
//这两个方法是抽象方法 要子类去实现
primitiveOperation1();
primitiveOperation2();
//共有的实现
concreteOperation();
hook();
}
abstract void primitiveOperation1();
abstract void primitiveOperation2();
//这个方法被定义为final的 子类无法覆盖 为模板方法使用或者子类使用
final void concreteOperation() {
//具体的实现
}
//没有具体的实现 也没有被定义为final
//这就是一个钩子方法 默认是不做任何事情 子类可以根据情况看要不要覆盖
void hook() {}
}
介绍下钩子方法>>
钩子是一种被声明在抽象类中的方法,但是有空的实现或者默认的实现,
钩子的存在可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类自己去决定
用途:1.可以根据需要去扩展(有默认的实现 如果子类要更改可以覆盖)
2.钩子能够作为条件控制,影响算法中的流程
如:
abstract class AbstractClass{
//定义了算法的结构 final型的就是防止子类去更改算法的接口
final void tempalteMethod() {
//这两个方法是抽象方法 要子类去实现
primitiveOperation1();
primitiveOperation2();
//共有的实现
if(hook()) { //在这里控制算法的走向
concreteOperation();
}
}
abstract void primitiveOperation1();
abstract void primitiveOperation2();
//这个方法被定义为final的 子类无法覆盖 为模板方法使用或者子类使用
final void concreteOperation() {
//具体的实现
}
//没有具体的实现 也没有被定义为final
//这就是一个钩子方法 默认是不做任何事情 子类可以根据情况看要不要覆盖
booleanhook() {return true;}
}
挖掘我们身边使用的模板方式:
Arrays.sort(Object[] objects) 这个就是一个模板方法 需要Object对象 自己实现Comparable接口
当比较两个对象大小的时候就是通过实现的compareTo()方法来知道 谁大谁小,而这个大小规则是由类自己去决定的,
比较的过程是这样的 先Object[0].compareTo(object[1]) 如果次序不对 就swap(),持续调整执行 执导比较完成。
很多人估计不认为这是一个模板方法,我们看问题不要太死板,要灵活 模板方式的重点是 提供一个算法,并让子类实现某些步骤,这里就是这样的 Arrays.sort()提供了一个算法,但是没有实现compareTo方法 必须子类去实现。