定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这个模式也是很简单但是特别有用的一个模式。目的都是封装不变部分,扩展可变部分,随便都可以举很多例子啦,比如造房子,顺序都是不变的,唯一变化的可能就是每个步骤用的材料不同,或者形状不同。下面我们来学习下吧(真的很简单很有用)。
1、例子
我们这里举个玩游戏的例子,玩游戏的不变部分是玩游戏的步骤,都是初始化游戏、开始游戏、游戏进行中、游戏结束,可变部分是具体初始化里面的逻辑以及各个环节的逻辑不通。
2、UML
这里模板方法play()设置为 final,这样它就不会被重写。因为顺序是绝对不会变的。
3、Game
/**
* @author suibibk.com
*/
public abstract class Game {
public abstract void init();
public abstract void start();
public abstract void ing();
public abstract void end();
//模板方法,已经规定好了执行逻辑顺序,不可重写,用final修饰
public final void paly() {
init();
start();
ing();
end();
}
}
4、GameA、GameB
这里只需要实现自己的可变部分即可。
/**
* @author suibibk.com
*/
public class GameA extends Game {
@Override
public void init() {
System.out.println("初始化游戏A");
}
@Override
public void start() {
System.out.println("开始游戏A");
}
@Override
public void ing() {
System.out.println("游戏A进行中");
}
@Override
public void end() {
System.out.println("游戏A已结束");
}
}
/**
* @author suibibk.com
*/
public class GameB extends Game {
@Override
public void init() {
System.out.println("初始化游戏B");
}
@Override
public void start() {
System.out.println("开始游戏B");
}
@Override
public void ing() {
System.out.println("游戏B进行中");
}
@Override
public void end() {
System.out.println("游戏B已结束");
}
}
5、测试类Test
/**
* @author suibibk.com
*/
public class Test {
public static void main(String[] args) {
Game a = new GameA();
a.paly();
System.out.println("---------------------");
Game b = new GameB();
b.paly();
}
}
运行会得到如下结果
初始化游戏A
开始游戏A
游戏A进行中
游戏A已结束
---------------------
初始化游戏B
开始游戏B
游戏B进行中
游戏B已结束
so easy
总结
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。