模板方法模式:优雅地封装算法骨架
在软件设计中,我们经常遇到这样的场景:多个类有相同的算法流程,但某些步骤的具体实现各不相同。模板方法模式通过定义算法骨架、延迟具体实现,完美解决了代码重复和流程控制问题。
一、真实案例:支付流程的烦恼
想象一下,你正在开发一个电商应用,需要接入多种支付方式:
// ❌ 重复的支付流程代码
class AlipayProcessor {fun processPayment(order: Order): PaymentResult {// 验证订单if (order.amount <= 0) throw IllegalArgumentException("金额无效")if (order.currency.isBlank()) throw IllegalArgumentException("货币无效")// 执行支付val transaction = alipayClient.pay(order.amount, order.currency)// 处理结果if (transaction.success) {order.status = OrderStatus.PAIDdatabase.updateOrder(order)notifyUser(order.userId, "支付成功")return PaymentResult.Success(transaction.id)} else {notifyUser(order.userId, "支付失败: ${transaction.error}")return PaymentResult.Failure(transaction.error)}}
}class WechatPayProcessor {fun processPayment(order: Order): PaymentResult {// 同样的验证逻辑,重复编写!if (order.amount <= 0) throw IllegalArgumentException("金额无效")if (order.currency.isBlank()) throw IllegalArgumentException("货币无效")// 不同的支付实现val transaction = wechatPayClient.createPayment(order)// 同样的结果处理逻辑,重复编写!if (transaction.isSuccess) {order.status = OrderStatus.PAIDdatabase.updateOrder(order)notifyUser(order.userId, "支付成功")return PaymentResult.Success(transaction.transactionId)} else {notifyUser(order.userId, "支付失败: ${transaction.errMsg}")return PaymentResult.Failure(transaction.errMsg)}}
}问题很明显:
- ✅ 支付流程相同(验证→执行→更新订单→通知用户) 
- ❌ 相同逻辑被重复实现 
- ❌ 添加新支付方式需要重写所有逻辑 
- ❌ 修改流程需要修改所有处理器 
二、模板方法模式登场
2.1 模式结构
模板方法模式包含两个核心部分:
- 抽象模板类:定义算法骨架 
- 具体实现类:实现特定步骤 
classDiagramclass PaymentProcessor {<<abstract>>+processPayment() PaymentResult#validateOrder() void#updateOrderStatus() void#notifyUser() void+executePayment()* PaymentTransaction+handleResult()* PaymentResult}class AlipayProcessor {+executePayment() PaymentTransaction+handleResult() PaymentResult}class WechatPayProcessor {+executePayment() PaymentTransaction+handleResult() PaymentResult}PaymentProcessor <|-- AlipayProcessorPaymentProcessor <|-- WechatPayProcessor2.2 重构支付系统
// ✅ 使用模板方法模式重构
abstract class PaymentProcessor {// 模板方法 - 定义支付流程骨架fun processPayment(order: Order): PaymentResult {return try {validateOrder(order)           // 步骤1:验证订单val transaction = executePayment(order) // 步骤2:执行支付(抽象)updateOrderStatus(order, transaction) // 步骤3:更新订单notifyUser(order, transaction) // 步骤4:通知用户handleResult(transaction)     // 步骤5:处理结果(抽象)} catch (e: Exception) {handleError(order, e)         // 错误处理}}// 具体方法 - 通用实现private fun validateOrder(order: Order) {require(order.amount > 0) { "支付金额必须大于0" }require(order.currency.isNotBlank()) { "货币类型不能为空" }require(order.userId.isNotBlank()) { "用户ID不能为空" }println("✅ 订单验证通过")}private fun updateOrderStatus(order: Order, transaction: PaymentTransaction) {order.status = OrderStatus.PAIDorder.transactionId = transaction.idorder.updatedAt = System.currentTimeMillis()database.updateOrder(order)println("✅ 订单状态已更新")}private fun notifyUser(order: Order, transaction: PaymentTransaction) {val message = if (transaction.isSuccess) {"支付成功,订单号: ${order.id}"} else {"支付失败: ${transaction.errorMessage}"}notificationService.send(order.userId, message)println("✅ 用户已通知")}// 钩子方法 - 可选重写protected open fun handleError(order: Order, error: Exception): PaymentResult {println("❌ 支付处理失败: ${error.message}")notificationService.send(order.userId, "支付处理失败: ${error.message}")return PaymentResult.Failure(error.message ?: "未知错误")}// 抽象方法 - 子类必须实现protected abstract fun executePayment(order: Order): PaymentTransactionprotected abstract fun handleResult(transaction: PaymentTransaction): PaymentResult
}// 具体支付实现变得非常简单
class AlipayProcessor : PaymentProcessor() {override fun executePayment(order: Order): PaymentTransaction {println("🔵 支付宝支付执行中...")// 支付宝特定的支付逻辑return alipayClient.pay(order.amount, order.currency)}override fun handleResult(transaction: PaymentTransaction): PaymentResult {// 支付宝特定的结果处理return if (transaction.success) {PaymentResult.Success(transaction.id, "支付宝支付成功")} else {PaymentResult.Failure(transaction.error ?: "支付宝支付失败")}}
}class WechatPayProcessor : PaymentProcessor() {override fun executePayment(order: Order): PaymentTransaction {println("🟢 微信支付执行中...")// 微信支付特定的逻辑return wechatPayClient.createPayment(order)}override fun handleResult(transaction: PaymentTransaction): PaymentResult {// 微信支付特定的结果处理return if (transaction.isSuccess) {PaymentResult.Success(transaction.transactionId, "微信支付成功")} else {PaymentResult.Failure(transaction.errMsg ?: "微信支付失败")}}// 重写错误处理钩子override fun handleError(order: Order, error: Exception): PaymentResult {println("❌ 微信支付处理失败,进行特殊处理")// 微信支付特定的错误处理逻辑wechatPayClient.rollback(order.id)return super.handleError(order, error)}
}三、Android 中的真实应用
3.1 Activity 生命周期模板
Android 框架本身就是模板方法模式的典范:
// Android Framework 中的模板方法
abstract class Activity {// 模板方法 - 控制Activity创建流程fun onCreate(savedInstanceState: Bundle?) {initializeWindow()      // 步骤1:窗口初始化(框架控制)setContentView()        // 步骤2:设置布局(框架控制)  onInitView()           // 步骤3:视图初始化(子类实现)onBindData()           // 步骤4:数据绑定(子类实现)onReady()              // 步骤5:准备完成(钩子方法)}private fun initializeWindow() {// Android框架控制的窗口初始化window.setBackgroundDrawableResource(android.R.color.background_light)}private fun setContentView() {// 调用抽象方法获取布局setContentView(getLayoutId())}// 抽象方法 - 子类必须实现protected abstract fun getLayoutId(): Intprotected abstract fun onInitView()protected abstract fun onBindData()// 钩子方法 - 子类可选择实现protected open fun onReady() {// 默认空实现}
}// 具体Activity实现
class MainActivity : Activity() {private lateinit var viewModel: MainViewModelprivate lateinit var recyclerView: RecyclerViewoverride fun getLayoutId(): Int = R.layout.activity_mainoverride fun onInitView() {// 只需关注视图初始化recyclerView = findViewById(R.id.recyclerView)recyclerView.layoutManager = LinearLayoutManager(this)findViewById<Button>(R.id.btnSubmit).setOnClickListener {onSubmit()}}override fun onBindData() {// 只需关注数据绑定viewModel = ViewModelProvider(this).get(MainViewModel::class.java)viewModel.items.observe(this) { items ->recyclerView.adapter = ItemAdapter(items)}}// 重写钩子方法添加额外逻辑override fun onReady() {super.onReady()// 添加额外的初始化逻辑setupAnalytics()checkNotifications()}private fun setupAnalytics() {// 分析工具初始化}private fun checkNotifications() {// 通知检查逻辑}
}3.2 网络请求模板
// 网络请求模板
abstract class NetworkRequestTemplate<T> {// 模板方法suspend fun execute(): Result<T> {showLoading()                    // 步骤1:显示加载validateRequest()               // 步骤2:验证请求val response = performRequest() // 步骤3:执行请求(抽象)val result = handleResponse(response) // 步骤4:处理响应(抽象)hideLoading()                   // 步骤5:隐藏加载return result}// 具体方法private fun showLoading() {// 通用加载显示逻辑loadingState.value = true}private fun hideLoading() {// 通用加载隐藏逻辑loadingState.value = false}private fun validateRequest() {// 通用验证逻辑require(getUrl().isNotBlank()) { "请求URL不能为空" }}// 抽象方法protected abstract fun getUrl(): Stringprotected abstract suspend fun performRequest(): Responseprotected abstract fun handleResponse(response: Response): Result<T>// 钩子方法protected open fun onError(error: Exception): Result<T> {// 默认错误处理return Result.failure(error)}
}// 具体请求实现
class LoginRequest(private val username: String,private val password: String
) : NetworkRequestTemplate<User>() {override fun getUrl(): String = "${BASE_URL}/api/login"override suspend fun performRequest(): Response {return httpClient.post(getUrl()) {body = json {"username" to username"password" to password}}}override fun handleResponse(response: Response): Result<User> {return if (response.status.isSuccess()) {val user = parseUser(response.body)Result.success(user)} else {Result.failure(Exception("登录失败: ${response.status}"))}}// 重写错误处理override fun onError(error: Exception): Result<User> {// 登录特定的错误处理analytics.trackLoginError(error)return super.onError(error)}
}四、模板方法模式的最佳实践
4.1 何时使用模板方法模式?
✅ 适合场景:
- 多个类有相同算法骨架,但某些步骤实现不同 
- 需要控制子类扩展,防止算法结构被破坏 
- 重要算法需要统一的执行顺序 
- 框架设计,希望用户遵循特定流程 
❌ 不适合场景:
- 算法步骤经常变化(考虑策略模式) 
- 只有少数步骤不同(考虑函数参数化) 
- 类层次结构过于复杂 
4.2 设计原则
// ✅ 好的模板方法设计
abstract class WellDesignedTemplate {// 模板方法应该是 final 的fun execute(): Result {step1()           // 固定步骤step2()           // 固定步骤  val data = step3() // 可变步骤(抽象)return step4(data) // 可变步骤(抽象)}// 具体方法 - 提供默认实现private fun step1() { /* 通用逻辑 */ }private fun step2() { /* 通用逻辑 */ }// 抽象方法 - 数量适中(2-5个)protected abstract fun step3(): Dataprotected abstract fun step4(data: Data): Result// 钩子方法 - 提供扩展点protected open fun onComplete(result: Result) {// 默认空实现}
}// ❌ 不好的设计
abstract class PoorlyDesignedTemplate {// 模板方法不是 final,容易被误改open fun execute() { /* ... */ }// 抽象方法过多,子类负担重abstract fun step1(): Dataabstract fun step2(): Dataabstract fun step3(): Dataabstract fun step4(): Dataabstract fun step5(): Data
}4.3 与策略模式的区别
很多人容易混淆模板方法模式和策略模式,它们的区别在于:
| 方面 | 模板方法模式 | 策略模式 | 
|---|---|---|
| 重点 | 算法骨架和流程控制 | 算法实现的互换 | 
| 继承关系 | 使用类继承 | 使用对象组合 | 
| 运行时 | 编译时确定结构 | 运行时切换算法 | 
| 代码复用 | 通过继承复用代码 | 通过组合复用算法 | 
// 模板方法模式 - 控制流程
abstract class ReportGenerator {// 固定生成流程fun generateReport(): Report {val data = fetchData()      // 抽象方法val processed = process(data) // 抽象方法return format(processed)    // 具体方法}abstract fun fetchData(): Dataabstract fun process(data: Data): ProcessedDataprivate fun format(data: ProcessedData): Report = TODO()
}// 策略模式 - 互换算法
class DataProcessor(private val strategy: ProcessingStrategy) {// 可互换的处理算法fun process(data: Data): Result {return strategy.execute(data) // 委托给策略对象}
}
interface ProcessingStrategy {fun execute(data: Data): Result
}五、实际项目中的收益
在我们重构支付系统后,获得了显著收益:
5.1 代码质量提升
重构前:
- 每个支付处理器 50+ 行代码 
- 重复代码率 60%+ 
- 添加新支付方式需要 1-2 天 
重构后:
- 父类 40 行通用逻辑 
- 每个子类 10-15 行特定逻辑 
- 添加新支付方式只需 1-2 小时 
5.2 维护性提升
// 添加新支付方式变得非常简单
class PayPalProcessor : PaymentProcessor() {override fun executePayment(order: Order): PaymentTransaction {println("🔵 PayPal支付执行中...")return payPalClient.createPayment(order)}override fun handleResult(transaction: PaymentTransaction): PaymentResult {return if (transaction.status == "COMPLETED") {PaymentResult.Success(transaction.id, "PayPal支付成功")} else {PaymentResult.Failure(transaction.error ?: "PayPal支付失败")}}
}// 业务流程修改只需改一处
abstract class PaymentProcessor {fun processPayment(order: Order): PaymentResult {validateOrder(order)logPaymentStart(order) // ✅ 新增步骤:只需在父类添加val transaction = executePayment(order)updateOrderStatus(order, transaction)notifyUser(order, transaction)logPaymentEnd(transaction) // ✅ 新增步骤:只需在父类添加return handleResult(transaction)}private fun logPaymentStart(order: Order) {analytics.track("payment_started", order.id)}private fun logPaymentEnd(transaction: PaymentTransaction) {analytics.track("payment_completed", transaction.id)}
}六、总结
模板方法模式通过"好莱坞原则"(不要调用我们,我们会调用你)实现了:
- 代码复用 - 将通用算法逻辑提升到父类 
- 流程控制 - 确保算法执行顺序一致性 
- 扩展灵活 - 通过钩子方法支持未来扩展 
- 维护简单 - 修改算法只需修改父类 
适用场景:
- Android Activity/Fragment 基类设计 
- 业务流程处理器(支付、订单、审批等) 
- 框架和库的设计 
- 任何有固定流程但不同实现的场景 
模板方法模式是构建可维护、可扩展系统的利器。下次当你发现多个类有相似流程时,考虑使用模板方法模式来消除重复,让代码更加优雅!
