什么是模版模式?
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
优点
- 封装不变部分,扩展可变部分。
- 提取公共代码,便于维护。
- 行为由父类控制,子类实现。
缺点
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景
- 有多个子类共有的方法,且逻辑相同,功能目的相同。
- 重要的、复杂的方法,可以考虑作为模板方法,提升系统可维护性。
示例
如下为模版模式的一个示例,React 当中的所有生命周期钩子方法其实就是典型的模版模式,组件要继承 React.Component。组件的生命周期是固定的,不会允许外部随意修改,定义这些钩子函数的作用就是给自定义组件,在特定生命周期节点上,扩展能力用的。
class MyComponent extends React.Component {
componentDidMount() {
console.log("组件已完成挂载。")
}
render() {
console.log("组件渲染。")
return <div>"Hello World"</div>;
}
}
另外一个想到的应用是 Java 的 Tread 类,封装了绝大部分复杂逻辑,包括对 JVM native 方法 start0 的调用,还有 Thread 生命周期管理等等。我们在创建新线程时,我们需要定义一个实现了 Runnable 接口的自定义类,然后以静态代理的方式交给 Thread 类去启动,我们只需要关心 run 方法内的实现即可。
public class Main {
public static void main(String[] args) {
System.out.println("Main Start");
new Thread(new MyThread()).start();
System.out.println("Main End");
}
static class MyThread implements Runnable {
@Override
public void run() {
System.out.println("Hello world");
}
}
}
Output:
Main Start
Main End
Hello world
在真实的业务需求中,模版模式应用非常广泛,例如下单接口中通常需要进行数据校验,创建订单,发送邮件等一系列的操作,为此我们可以定制一个下单流程的模版,把以上各环节写成抽象方法,而具体的实现留个各个不同订单类型自己去实现。
interface BookingService {
default void book(String userName, String email) {
validate(userName);
createOrder(userName);
sendNotification(email);
}
void validate(String userName);
void createOrder(String userName);
void sendNotification(String email);
}
class MovieBookingService implements BookingService {
@Override
public void validate(String userName) {
System.out.println(String.format("[%s] has passed validation", userName));
}
@Override
public void createOrder(String userName) {
System.out.println(String.format("Movie order for user: [%s] has been created", userName));
}
@Override
public void sendNotification(String email) {
System.out.println(String.format("Movie order email: [%s] has been sent", email));
}
}
public class Main {
public static void main(String[] arg) {
BookingService service = new MovieBookingService();
service.book("Lucien", "lucien.chen@123.com");
}
}
Output:
[Lucien] has passed validation
Movie order for user: [Lucien] has been created
Movie order email: [lucien.chen@123.com] has been sent