Zer0e's Blog

设计模式之模板方法模式

字数统计: 924阅读时长: 3 min
2020/09/08 Share

前言

本篇聊聊模板方法模式。

正文

概念

模板方法模式属于行为型模式,它定义一个模板结构,然后让其子类去实现。其主要作用是提高代码的复用性,并且在不改变模板的情况下子类能重写方法。
那这种设计模式就十分常见了,在父类中定义执行顺序,子类再去具体的去实现,这就是模板方法模式。

实现

举个例子,比如我们平常去超市买东西,基本上分为几个步骤,拿购物车或篮子,挑选商品,结算。那就用这个例子来写写代码。

未使用模板方法模式

首先我们一般来说我们是先定义一个父类,然后子类再去实现父类方法。也就是没使用模板方法模式时,我们可能会这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class AbstractClass {
// 拿购物车
public abstract void getShoppingCart();

// 挑选商品
public abstract void selectGoods();

// 结算
public abstract void pay();

// 全流程
public abstract void shopping();
}

那在子类当中,我们可能这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ShoppingByOnlinePay extends AbstractClass{
@Override
public void getShoppingCart() {
System.out.println("获取购物车");
}

@Override
public void selectGoods() {
System.out.println("挑选商品");
}

@Override
public void pay() {
System.out.println("使用网上支付");
}

@Override
public void shopping() {
getShoppingCart();
selectGoods();
pay();
}
}

那这样写就是在抽象类中不写任何逻辑,所有的实现都在子类中实现,如果后续有问题也较好发现,但我们可以发现,其实shopping方法是固定的,也就是流程固定,那么我们这些代码是不是可以移动到抽象类中呢?是的,可以,这就是模板方法模式。

使用模板方法

我们重写下抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class AbstractClass {
// 拿购物车
protected abstract void getShoppingCart();

// 挑选商品
protected abstract void selectGoods();

// 结算
protected abstract void pay();

// 全流程
public final void shopping(){
this.getShoppingCart();
this.selectGoods();
this.pay();
}
}

我们将子类需要重写的方法定义为protected,因为这些方法不需要暴露给其他类,只需要子类自己实现即可,然后我们把购物流程在抽象类中以final修饰,因为流程固定不需要修改。
我们接着写现金付款和网上支付两种结算方式的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ShoppingByOnlinePay extends AbstractClass{
@Override
protected void getShoppingCart() {
System.out.println("获取购物车");
}

@Override
protected void selectGoods() {
System.out.println("挑选商品");
}

@Override
protected void pay() {
System.out.println("使用网上支付");
}
}
public class ShoppingByCash extends AbstractClass{
@Override
protected void getShoppingCart() {
System.out.println("获取购物车");
}

@Override
protected void selectGoods() {
System.out.println("挑选商品");
}

@Override
protected void pay() {
System.out.println("使用现金结算");
}
}

那这里调用就很简单,我就不写了,直接调用shopping方法即可。
如此,我们就使用模板方法模式实现了这个简单的例子。

优缺点

模板方法模式具有良好的封装性,即把一成不变的代码封装在父类当中,而子类去实现基本方法的逻辑,并且扩展性良好,符合开闭原则和单一职责原则。那最重要的还是复用了重复代码。
那缺点嘛,可能就是实现类都需要单独的子类去实现,可能会增加类的数量,但我个人认为这个其实严格来说不能说是缺点,除非是实现的种类存在几十种上百种。当然,仁者见仁智者见智,算不算缺点只有在用到的时候才能知道。

CATALOG
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 概念
    2. 2.2. 实现
    3. 2.3. 未使用模板方法模式
    4. 2.4. 使用模板方法
    5. 2.5. 优缺点