簡介
假設你要沖泡咖啡和茶,兩者的流程相似但部分步驟不同:
- 燒水(公共步驟)
- 加入主材料(咖啡粉/茶葉)
- 添加調料(糖/牛奶)→ 可選步驟
- 倒進杯子(公共步驟)
模板模式的作用:
- 在父類中定義沖泡飲料的固定流程(如燒水、倒杯),子類只需實現差異步驟(如加咖啡粉或茶葉)。
- 避免重復代碼,同時允許靈活擴展(如是否加調料)。
適用場景:
- 多個類有相同流程,但某些步驟實現不同(如數據處理、文件解析)。
- 需要控制子類的擴展點(如鉤子方法)。
優點:
- 代碼復用:公共邏輯在父類實現。
- 靈活擴展:子類只需關注差異步驟。
缺點:
- 父類定義流程,子類可能被限制靈活性。
- 容易因父類修改影響所有子類。
代碼
// 抽象模板類:定義飲料沖泡流程
abstract class BeverageTemplate {// 模板方法(final 防止子類覆蓋)public final void prepareBeverage() {boilWater();brew();addCondiments(); // 鉤子方法(可選步驟)pourInCup();}// 公共步驟private void boilWater() {System.out.println("燒水");}private void pourInCup() {System.out.println("倒進杯子");}// 抽象方法:子類必須實現protected abstract void brew();// 鉤子方法(默認不添加調料,子類可選覆蓋)protected void addCondiments() {}
}// 具體子類:咖啡
class Coffee extends BeverageTemplate {protected void brew() {System.out.println("加入咖啡粉");}@Overrideprotected void addCondiments() {System.out.println("加糖和牛奶");}
}// 具體子類:茶
class Tea extends BeverageTemplate {protected void brew() {System.out.println("加入茶葉");}
}// 客戶端代碼
public class Client {public static void main(String[] args) {BeverageTemplate coffee = new Coffee();coffee.prepareBeverage();// 輸出:// 燒水 → 加入咖啡粉 → 加糖和牛奶 → 倒進杯子BeverageTemplate tea = new Tea();tea.prepareBeverage();// 輸出:// 燒水 → 加入茶葉 → 倒進杯子}
}
類圖
@startuml
abstract class BeverageTemplate {+ prepareBeverage(): void- boilWater(): void- pourInCup(): void# brew(): void# addCondiments(): void
}class Coffee {# brew(): void# addCondiments(): void
}class Tea {# brew(): void
}BeverageTemplate <|-- Coffee
BeverageTemplate <|-- Tea
@enduml
場景
數據庫連接、執行SQL、關閉連接的固定流程。
// 抽象模板類
public abstract class JdbcTemplate {// 模板方法public final void execute() {connect();String sql = buildSql(); // 抽象方法executeSql(sql);close();}private void connect() {System.out.println("連接數據庫");}private void executeSql(String sql) {System.out.println("執行SQL: " + sql);}private void close() {System.out.println("關閉連接");}protected abstract String buildSql();
}// 具體子類:用戶查詢
class UserQuery extends JdbcTemplate {protected String buildSql() {return "SELECT * FROM users";}
}// 具體子類:訂單插入
class OrderInsert extends JdbcTemplate {protected String buildSql() {return "INSERT INTO orders VALUES (...)";}
}// 客戶端代碼
public class DatabaseClient {public static void main(String[] args) {JdbcTemplate userQuery = new UserQuery();userQuery.execute();// 輸出:// 連接數據庫 → 執行SQL: SELECT * FROM users → 關閉連接JdbcTemplate orderInsert = new OrderInsert();orderInsert.execute();// 輸出:// 連接數據庫 → 執行SQL: INSERT INTO orders... → 關閉連接}
}