1.定义:
在一个方法中定义一个算法的骨架,而将一些具体操作延迟到子类实现。
2.组成:
模板方法模式基于抽象类实现,抽象类中由三类方法组成:
-
使用final定义的模板方法:用来定义共同的操作步骤
-
使用final定义的普通方法:用来实现共同的具体操作
使用final定义的方法,子类都只能继承,不能覆写 -
使用abstract定义的抽象方法:用来实现不同的具体操作,要求子类必须覆写
3.代码实现:
package www.first;
abstract class MakeMilkTea{
//模板方法--实现每个业务的共同操作流程
//子类只能继承不能覆写
final void makeStep(){
preWater();
addSomething();
mixIt();
}
//具体的共同操作在此实现
final void preWater(){
System.out.println("Boiling Water");
}
final void mixIt(){
System.out.println("Mixing it");
}
//抽象方法--子类必须覆写
//用来实现不同的具体操作
abstract void addSomething();
}
class PearlMilkTea extends MakeMilkTea{
@Override
void addSomething() {
System.out.println("Adding Pearl");
}
}
class RedBeanMilkTea extends MakeMilkTea{
@Override
void addSomething() {
System.out.println("Adding Red Bean");
}
}
public class Method {
public static void main(String[] args) {
MakeMilkTea milkTea = new RedBeanMilkTea();
milkTea.makeStep();
}
}
结果如下:
4.分析及优化:其实我们还可以在模板方法中加一个"钩子"方法,用来扩展功能,不使用abstract或final去修饰它,子类可以选择性的覆写该方法。而且实例化对象时我们可以采用工厂类,利用反射,这样方便客户端的操作。实现如下:
package www.first;
import java.util.Scanner;
abstract class MakeMilkTea{
//模板方法--实现每个业务的共同操作流程
//子类只能继承不能覆写
final void makeStep(){
preWater();
addSomething();
mixIt();
}
//具体的共同操作在此实现
final void preWater(){
System.out.println("Boiling Water");
}
final void mixIt(){
System.out.println("Mixing it");
}
//抽象方法--子类必须覆写
//用来实现不同的具体操作
abstract void addSomething();
void hook(){}
}
class PearlMilkTea extends MakeMilkTea{
@Override
void addSomething() {
hook();
System.out.println("Adding Pearl");
}
//选择性覆写"钩子"方法
void hook(){
Scanner scanner = new Scanner(System.in);
System.out.println("Would you like to add sugar? yes/no");
String str = scanner.nextLine();
if("yes".equals(str)){
System.out.println("Adding Sugar");
}else{
return;
}
}
}
class RedBeanMilkTea extends MakeMilkTea{
@Override
void addSomething() {
System.out.println("Adding Red Bean");
}
}
//工厂类生成实例化对象
class MilkFactory{
public static MakeMilkTea getInstance(String str) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> cls = Class.forName("www.first."+str);
MakeMilkTea milkTea = (MakeMilkTea) cls.newInstance();
return milkTea;
}
}
public class Method {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
Scanner scanner = new Scanner(System.in);
System.out.println("What would you like to drink?");
String str = scanner.nextLine();
MakeMilkTea milkTea = MilkFactory.getInstance(str);
milkTea.makeStep();
}
}
可以看出,我在PearlMilkTea类中选择覆写了hook();实现了"加糖"这一扩展操作,结果如下:
5.优点:
- 降低了系统的耦合
- 实现代码复用
- 符合OCP原则