模板方法 Template Method
模板方法模式是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
🔖 通常是对算法的特定步骤进行优化,而不是对整个算法进行修改。
为什么要使用?
模板方法模式的对象职责:
在父类中定义处理流程的框架,在子类中实现具体处理。
👉 期望在一个通用的算法或流程框架下进行自定义开发。
👉 避免同样的代码逻辑进行重复编码。
💡 模板方法模式将通用操作和流程处理交给父类处理,其他具体操作交由子类实现。
模式结构
- 抽象类(Abstract Class)会声明作为算法步骤的方法,以及依次调用它们的实际模板方法。算法步骤可以被声明为
abstract
类型,也可以提供一些默认实现。
- 具体类(Concrete Class)可以重写所有步骤,但不能重写模板方法自身。
模板方法模式的类图:
模式实现
该示例使用模板方法模式将 display
操作交由父类实现,其他操作由子类(显示单个字符的类 CharDisplay
和显示整个字符串的类 StringDisplay
)实现,display
主要负责控制 open
,print
,close
的调用顺序。
示例程序的类图
代码实现
抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package example;
public abstract class AbstractDisplay { public abstract void open();
public abstract void print();
public abstract void close();
public final void display() { open(); print(); close(); } }
|
具体类
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
| package example;
public class CharDisplay extends AbstractDisplay { private char ch;
public CharDisplay(char ch) { this.ch = ch; }
@Override public void open() { System.out.print("<<"); }
@Override public void print() { System.out.print(ch); }
@Override public void close() { System.out.println(">>"); } }
|
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package example;
public class StringDisplay extends AbstractDisplay { private String str;
public StringDisplay(String str) { this.str = str; }
@Override public void open() { System.out.print("+"); for (int i = 0; i < str.length(); i++) { System.out.print("-"); } System.out.println("+"); }
@Override public void print() { printLine(); System.out.print("|"); for (int i = 0; i < str.length(); i++) { System.out.print(str.charAt(i)); } System.out.println("|"); printLine(); }
@Override public void close() { System.out.print("+"); for (int i = 0; i < str.length(); i++) { System.out.print("-"); } System.out.println("+"); }
private void printLine() { System.out.print("|"); for (int i = 0; i < str.length(); i++) { System.out.print("-"); } System.out.println("|"); } }
|
代码测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import example.AbstractDisplay; import example.CharDisplay; import example.StringDisplay;
public class Test { public static void main(String[] args) { AbstractDisplay charDisplay = new CharDisplay('H'); AbstractDisplay stringDisplay = new StringDisplay("Hellovie"); System.out.println("CharDisplay实现"); charDisplay.display(); System.out.println("\n----------------- 分割线 -----------------\n"); System.out.println("StringDisplay实现"); stringDisplay.display(); } }
|
输出结果
1 2 3 4 5 6 7 8 9 10 11
| CharDisplay实现: <<H>>
----------------- 分割线 -----------------
StringDisplay实现: +--------+ |--------| |Hellovie| |--------| +--------+
|
常用场景和解决方案
- 多个类有相同的方法并且逻辑可以共用时。
- 将通用的算法或固定流程设计为模板,在每一个具体的子类中再继续优化算法步骤或流程步骤时。
- 重构超长代码时,发现某一个经常使用的共有方法。
- 当你只希望客户端扩展某个特定算法步骤,而不是整个算法或其结构时。
模式的优缺点
优点 |
缺点 |
你可仅允许客户端重写一个大型算法中的特定部分,使得算法其他部分修改对其所造成的影响减小。 |
部分客户端可能会受到算法框架的限制。 |
你可将重复代码提取到一个超类中,有效去除重复代码。 |
通过子类抑制默认步骤实现可能会导致违反里氏替换原则。 |
有助于找到更通用的模板。 |
模板方法中的步骤越多,其维护工作就可能会越困难。 |
拓展知识
- 工厂方法模式是模板方法模式的一种特殊形式。同时,工厂方法可以作为一个大型模板方法中的一个步骤。
- 继承的结构容易带来“修改一个类而影响所有类”的情况。
🔙 设计模式
📌最后:希望本文能够给您提供帮助,文章中有不懂或不正确的地方,请在下方评论区💬留言!
🔗参考文献:
🌐 设计模式 –refactoringguru
▶️ bilibili-趣学设计模式;黄靖锋. –拉勾教育
📖 图解设计模式 /(日)结城浩著;杨文轩译. –北京:人民邮电出版社,2017.1