模板方法模式
含义概述
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
使用场景
当有一个业务有 N 个步骤( 模板 ),其中一部分步骤是永恒不变的,那么就将不变的这些步骤抽象到父类中,可能变化的步骤留给子类去实现。
组成元素
- 模板方法:定义算法的整体流程,通常推荐使用 final 关键字修饰,防止子类重写,从而破坏了模板中规定好的流程
- 抽象方法:使用 abstract 修饰,让子类去实现
- 普通方法:父类提供默认实现,设置为private则不允许子类也可重写,设置为public或者proteced则允许子类重写,具体访问修饰符的级别设置可以根据需求设定,不做强制规定
- 钩子方法:模板方法中提前预埋多个钩子,让子类有一定的能力影响抽象类中的算法流程。
案例
- Servlet 中的模板方法:doGet()/doPost()/service()方法
- Arrays.sort() 方法,它要求对象实现 Comparable 接口
优缺点比较
模板方法模式是将子类中不变的部分抽象到父类,可变的部分由子类去实现。
-
优点
封装不变公共代码,便于维护。可变部分的代码由子类自由决定,扩展性强。 -
缺点
每新增一个不同的实现都需要增加一个子类,可能导致类数量变多,增加系统复杂性。
实例
Cook.java
public abstract class Cook {
/**
* 钩子的开关变量
*/
protected boolean needBeforeCook = false;
/**
* 钩子的开关
*
* @return
*/
protected boolean needBeforeCook() {
System.out.println("===钩子函数被禁用===");
return false;
}
/**
* 钩子函数
*/
public void beforeCook() {
}
public void open() {
System.out.println("打开抽油烟机");
}
public void fire() {
System.out.println("生火");
}
/**
* 期望子类去实现
*/
public abstract void doCook();
public void outfire() {
System.out.println("灭火");
}
public void close() {
System.out.println("关闭抽油烟机");
System.out.println("======收工=======");
}
/**
* 使用final关键字,防止子类重写
*/
public final void cook() {
// 默认开启钩子函数
if (this.needBeforeCook()) {
this.beforeCook();
}
this.open();
this.fire();
this.doCook();
this.outfire();
this.close();
}
}
CookMeat.java
/**
* 炒肉
*/
public class CookMeat extends Cook {
@Override
public boolean needBeforeCook() {
return true;
}
@Override
public void beforeCook() {
System.out.println("腌制");
}
@Override
public void doCook() {
System.out.println("红烧肉");
}
}
CookVegatables.java
public class CookVegatables extends Cook {
@Override
public void doCook() {
System.out.println("炒蔬菜");
}
}
单元测试
import com.netease.learn.designPattern.templateMethod.Cook;
import com.netease.learn.designPattern.templateMethod.CookMeat;
import com.netease.learn.designPattern.templateMethod.CookVegatables;
import org.junit.Test;
public class TemplateMethodTest {
@Test
public void test1() {
Cook cook = new CookMeat();
cook.cook();
}
@Test
public void test2() {
Cook cook = new CookVegatables();
cook.cook();
}
}
网友评论