author zong
email zongzhe1996@163.com
介绍
模板方法模式通过抽象方法,定义一个操作中算法的骨架,将一些步骤的具体实现下放到子类中实现。模板方法使得算法结构相同但是某些步骤有细微差距的地方可以灵活的进行调整。
应用场景
方法的大体流程通用,但是有些步骤在不同情况下的处理方式不同。
具体实现
操作的整个流程在抽象类中定义,流程中每个具体步骤的行为在实现类中定义。
模板方法的主要结构如下:
如图所示,在抽象类 AbstractTemplate
中定义了普通方法 templateMethod()
和抽象方法 abstractMethod()
,普通方法 templateMethod()
直接在类 AbstractTemplate
中实现,抽象方法 abstractMethod()
的具体实现则下放到子类 ConcreteTemplate
中实现。
首先,先定义抽象类:
public abstract class AbstractClass{
//定义抽象类中的三个不同的抽象方法
abstract void first();
abstract void second();
abstract void last();
//抽象类中的抽象方法执行顺序已经预先定义好了
public void run(){
first();
second();
last();
}
}
然后,根据不同子类的实际需求,定义抽象方法不同的实现方式。
//第一种子类的实现方式
public class SubclassOne extends AbstractClass{
void first(){
sout("One One One first !!!");
}
void second(){
sout("One One One second !!!");
}
void last(){
sout("One One One last !!!");
}
}
//第二种子类的实现方式
public class SubclassTwo extends AbstractClass{
void first(){
sout("Two Two Two first !!!");
}
void second(){
sout("Two Two Two second !!!");
}
void last(){
sout("Two Two Two last !!!");
}
}
在使用的过程中只需要根据实际需求,为抽象类的引用创建对应的子类实例即可得到相同框架算法的不同实现。
void main(){
//用第一个子类创建实例
AbstractClass ac = new SubclassOne();
//用抽象类中定义的执行顺序执行第一个子类中实现的三个方法。
ac.run();
}
总结
抽象类中的抽象方法经常被称为钩子方法,对于算法流程大体相同,但是,每个步骤不同的程序来说,非常好用,实现了算法步骤和算法框架的解耦过程。作者还没有看过Mybatis的源码,但是,个人觉得Mybatis应该用了模板方法模式。
根据模板方法模式,对Mybatis的源码结构的猜测如下:
//常用mysql访问代码大体结构如下:
class MysqlCon{
public void select(){
MysqlConnection con=new MysqlConnection();
con.start();
con.setSql("Select * from A...");
con.end;
con.close();
}
}
如上述代码所示,每一条sql语句都需要创建一个对应的方法,但是每个方法中如下部分都是相同的。
class MysqlCon{
public void select(){
MysqlConnection con=new MysqlConnection();
con.start();
......
con.end;
con.close();
}
}
只有sql语句相关的地方不相同,这样多个方法就会产生大量的重复代码。可以使用模板方法解决这个问题。
首先,创建钩子方法。并将设置sql语句的地方放到钩子方法中实现。
class MysqlCon{
//钩子方法
abstract String getSql();
public void select(){
MysqlConnection con=new MysqlConnection();
con.start();
//使用钩子方法
con.setSql(getSql());
con.end;
con.close();
}
}
然后,就可以在每次使用MysqlCon类的过程中实现getSql即可。
void main(){
MysqlCon mc=new MysqlCon(){
String getSql(){
return "Select * from A...";
}
};
mc.select();
}