設計模式是經過分類、歸納、總結的代碼設計經驗。合理運用模式能實現代碼復用、提升可讀性、保證可靠性。本文聚焦行為型模式中的模板方法模式,通過源碼級解析與實戰案例,掌握其「定義骨架、延遲細節」的精髓。
在一個操作中定義算法的骨架,將某些步驟延遲到子類實現。模板方法使得子類可以不改變算法結構的前提下,重新定義算法的某些特定步驟。
| 角色 | 職責 |
|---|---|
| AbstractClass(抽象類) | 實現模板方法,定義算法骨架;聲明抽象方法強制子類實現 |
| ConcreteClass(具體類) | 實現抽象方法,完成完整算法 |
場景:系統需支持 Excel、CSV、PDF 多種導出格式,流程固定為「數據查詢 → 格式轉換 → 文件寫入 → 响應下載」,其中「格式轉換」與「文件寫入」因格式而異。
// 抽象模板:定義導出算法骨架
public abstract class AbstractExporter<T> {
// 模板方法:final 防止子類破壞流程
public final void export(List<T> data, HttpServletResponse response) {
// 1. 通用預處理(設置響應頭等)
prepareResponse(response);
// 2. 核心變化點:格式轉換(子類實現)
byte[] content = convert(data);
// 3. 通用後處理(寫入輸出流)
writeResponse(content, response);
// 4. 釩勾子方法:子類可選覆寫
afterExport();
}
protected void prepareResponse(HttpServletResponse response) {
response.setContentType(getContentType());
response.setHeader("Content-Disposition", "attachment; filename=" + getFileName());
}
protected void writeResponse(byte[] content, HttpServletResponse response) throws IOException {
try (OutputStream os = response.getOutputStream()) {
os.write(content);
os.flush();
}
}
// 抽象方法:強制子類實現
protected abstract String getContentType();
protected abstract String getFileName();
protected abstract byte[] convert(List<T> data);
// 鉤子方法:默認空實現,子類可選覆寫
protected void afterExport() {}
}
// 具體實現:Excel 導出
public class ExcelExporter<T> extends AbstractExporter<T> {
@Override protected String getContentType() { return "application/vnd.ms-excel"; }
@Override protected String getFileName() { return "export_" + System.currentTimeMillis() + ".xls"; }
@Override protected byte[] convert(List<T> data) {
// 使用 Apache POI 實現 Excel 生成邏輯
return workbookToBytes(data);
}
}
// 具體實現:CSV 導出
public class CsvExporter<T> extends AbstractExporter<T> {
@Override protected String getContentType() { return "text/csv"; }
@Override protected String getFileName() { return "export_" + System.currentTimeMillis() + ".csv"; }
@Override protected byte[] convert(List<T> data) {
// CSV 字符串拼接邏輯
return csvToBytes(data);
}
}
final:防止子類覆寫破壞算法骨架順序。abstract):必須由子類實現(如 convert())afterExport()),提供擴展點不強制實現。java.io.InputStream.read():模板方法調用抽象 read(byte[])java.util.AbstractList.indexOf():模板遍歷調用抽象 get(int)javax.servlet.http.HttpServlet.service():分發 doGet/doPost 等抽象方法JdbcTemplate、RestTemplate 大量使用模板方法封裝資源管理、異常轉換等通用邏輯| 優點 | 缺點 |
|---|---|
|
|
適用場景:多個子類共享相同算法結構,僅局部步驟不同;複雜算法核心穩定、邊緣變化;框架設計中定義不可變的業務流程骨架。
模板方法模式以「骨架在父類、血肉在子類」的優雅方式,實現了最大程度的代碼復用與最小程度的耦合。掌握其「抽象方法強制實現、鉤子方法可選覆寫、模板方法 final 守護」三大設計精髓,是構建可擴展框架級代碼的關鍵技能。