介绍
模板方法是一种行为类设计模式。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
模板方法是一个定义在父类的方法(抽象类),具体实现由子类实现
优点:
1、封装不变部分,扩展可变部分。
2、提取公共代码,便于维护。
3、行为由父类控制,子类实现。
缺点:
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景:
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项:
1.为防止恶意操作,一般模板方法都加上 final 关键词,不允许被重写
2.抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限
实现
模拟场景:
汽车都有以下步骤:启动汽车、停止汽车、响喇叭、汽车跑起来...等等
UML图:
基础的汽车类
public abstract class Car {
protected abstract void start();
protected abstract void stop();
protected abstract void alarm();
final void run(){
start();
alarm();
stop();
}
}
宝马汽车:
public class BMWCar extends Car{
@Override
protected void start() {
System.out.println("BMW发动……");
}
@Override
protected void stop() {
System.out.println("BMW停止……");
}
@Override
protected void alarm() {
System.out.println("BMW响喇叭……");
}
}
奔驰汽车:
public class MercedesCar extends Car{
@Override
protected void start() {
System.out.println("Mercedes发动……");
}
@Override
protected void stop() {
System.out.println("Mercedes停止……");
}
@Override
protected void alarm() {
System.out.println("Mercedes响喇叭……");
}
}
测试运行:
public static void main(String[] args) {
Car bmw = new BMWCar();
bmw.run();
System.out.println("====================");
Car mercedes = new MercedesCar();
mercedes.run();
}
-------------------
BMW发动……
BMW响喇叭……
BMW停止……
====================
Mercedes发动……
Mercedes响喇叭……
Mercedes停止……
拓展延申
首先不是所有的汽车都会在运行的时候响喇叭(市区禁鸣),那这个时候我们该咋办呢?
解决方案如下:
修改 Car 添加一个是否能响喇叭的方法,让自身判断是否能响喇叭。同时子类需要增加相应的实现。
基础的汽车类
public abstract class Car {
protected abstract void start();
protected abstract void stop();
protected abstract void alarm();
protected abstract boolean isAlarm();
final void run(){
start();
if(isAlarm()){
alarm();
}
stop();
}
}
宝马汽车:
public class BMWCar extends Car{
@Override
protected void start() {
System.out.println("BMW发动……");
}
@Override
protected void stop() {
System.out.println("BMW停止……");
}
@Override
protected void alarm() {
System.out.println("BMW响喇叭……");
}
@Override
protected boolean isAlarm() {
System.out.println("我不经过市区可以响喇叭....");
return true;
}
}
奔驰汽车:
public class MercedesCar extends Car{
@Override
protected void start() {
System.out.println("Mercedes发动……");
}
@Override
protected void stop() {
System.out.println("Mercedes停止……");
}
@Override
protected void alarm() {
System.out.println("Mercedes响喇叭……");
}
@Override
protected boolean isAlarm() {
System.out.println("我天天经过市区塞车...还不可以响喇叭....");
return false;
}
}
测试运行:
BMW发动……
我不经过市区可以响喇叭....
BMW响喇叭……
BMW停止……
====================
Mercedes发动……
我天天经过市区塞车...还不可以响喇叭....
Mercedes停止……
延申涉及的钩子方法
在我们的Car
抽象类中isAlarm()
的返回值就是影响了模板方法的执行结果,该方法就叫做钩子方法(HookMethod)。