什么是模板方法模式?
模板方法模式是一种类行为型模式。
模板方法模式其实就是在不改变代码的情况下,实现了对某些步骤的重定义。
模板方法模式是一个结构比较简单的行为型设计模式,仅仅用到了继承的特性。模板方式将算法流程封装到父类方法中,而在子类中对个算法步骤进行不同的实现,从而实现不同的算法结果。
模板方法模式广泛应用生活中,比如我们常见的点餐系统,具体步骤概括来说就是落位→点餐→上餐→结账。这四个步骤对于每位来就餐的顾客都是相同的,不同的是每个步骤的具体细节,所以我们可以通过模板方法模式实现点餐系统。
核心结构
- AbstractClass。抽象类,在抽象类中,声明了基本操作方法,基本操作方法可以是具体实现,也可以是抽象的,完全交由子类实现。同时实现了一个总体的算法步骤方法,在步骤方法中对基本方法进行了组合,模板方法不仅可以调用抽象类中实现的基本方法,还可以调用子类的实现的基本方法,亦或是调用其他对象中的方法。
- ConcreteClass。实现类。继承自抽象类,用于实现或重写在父类中声明的基本方法,来完成具体的算法步骤。
由于目前JDK 8中已经支持接口中实现default方法,也就是我们也可以通过接口的方式作为AbstractClass。
类图展示
代码分析
由于模板方法模式的简单性,我们将简单的用之实现推送的场景。
首先我们需要定义一个抽象模板类:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/31.
* 模板方法模式——抽象模板
*/
public abstract class Template {
/**
* 调用模板方法
*/
public void message() {
title();
content();
extraFileds();
if (isTimingPush()) {
System.out.println("The message will be sent in the future");
} else {
System.out.println("The message is sending");
}
}
public abstract void title();
public abstract void content();
public abstract void extraFileds();
public abstract boolean isTimingPush();
public abstract boolean isNotification();
}
接着我们根据模板方法模式,定义两种推送场景。
Android推送场景:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/31.
* 模板方法模式——具体模板
*/
public class AndroidMessagePush extends Template {
@Override
public void message() {
super.message();
}
@Override
public void title() {
if (isNotification()) {
System.out.println("Android message's title is building");
}
}
@Override
public void content() {
System.out.println("Android message's contents building");
}
@Override
public void extraFileds() {
System.out.println("Android message's extra fields building");
}
@Override
public boolean isTimingPush() {
return false;
}
@Override
public boolean isNotification() {
return false;
}
}
iOS推送场景:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/31.
* 模板方法模式——具体模板
*/
public class IOSNotificationPush extends Template {
@Override
public void message() {
super.message();
}
@Override
public void title() {
if (isNotification()) {
System.out.println("IOS notification;s title building");
}
}
@Override
public void content() {
System.out.println("IOS notification's contents building");
}
@Override
public void extraFileds() {
System.out.println("IOS notification's extra fields building");
}
@Override
public boolean isTimingPush() {
return true;
}
@Override
public boolean isNotification() {
return true;
}
}
模板方法模式就是如此的简单,所以我们需要活学活用。
惯例,测试代码:
/**
* Created by sunshine on 2017/6/20.
* 模板方法模式测试
*/
public class TemplateTest {
public static void main(String[] args) {
Template androidMessagePush = new AndroidMessagePush();
androidMessagePush.message();
Template iOSNotificationPush = new IOSNotificationPush();
iOSNotificationPush.message();
}
}
模式总结
优点
- 代码复用,设计得当的话,大大减少了无用代码。
- 子类中可以根据钩子判断算法步骤是否执行,提高了系统设计的灵活性。
- 符合单一职责原则和开闭原则。不同的子类可以实现不同的抽象模板。
缺点
- 如果基于抽象模板的类过多,可能会造成系统的类急剧膨胀。
针对这种情形,我们可以使用结合桥接模式进行复合模式设计。
适用场景
- 算法步骤基本类似,具体实现略有不同。
- 代码重构,多个类中的公共代码可以提到父类中完成。
- 需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。