在软件设计中,我们经常遇到这样的场景:多个类有相同的算法流程,但某些步骤的具体实现各不相同。模板方法模式通过定义算法骨架、延迟具体实现,完美解决了代码重复和流程控制问题。
一、真实案例:支付流程的烦恼
想象一下,你正在开发一个电商应用,需要接入多种支付方式:
// ❌ 重复的支付流程代码
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.PAID
database.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.PAID
database.updateOrder(order)
notifyUser(order.userId, "支付成功")
return PaymentResult.Success(transaction.transactionId)
} else {
notifyUser(order.userId, "支付失败: ${transaction.errMsg}")
return PaymentResult.Failure(transaction.errMsg)
}
}
}
问题很明显:
-
✅ 支付流程相同(验证→执行→更新订单→通知用户)
-
❌ 相同逻辑被重复实现
-
❌ 添加新支付方式需要重写所有逻辑
-
❌ 修改流程需要修改所有处理器
二、模板方法模式登场
2.1 模式结构
模板方法模式包含两个核心部分:
-
抽象模板类:定义算法骨架
-
具体实现类:实现特定步骤
classDiagram
class 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 <|-- AlipayProcessor
PaymentProcessor <|-- WechatPayProcessor
2.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.PAID
order.transactionId = transaction.id
order.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): PaymentTransaction
protected 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(): Int
protected abstract fun onInitView()
protected abstract fun onBindData()
// 钩子方法 - 子类可选择实现
protected open fun onReady() {
// 默认空实现
}
}
// 具体Activity实现
class MainActivity : Activity() {
private lateinit var viewModel: MainViewModel
private lateinit var recyclerView: RecyclerView
override fun getLayoutId(): Int = R.layout.activity_main
override 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(): String
protected abstract suspend fun performRequest(): Response
protected 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(): Data
protected abstract fun step4(data: Data): Result
// 钩子方法 - 提供扩展点
protected open fun onComplete(result: Result) {
// 默认空实现
}
}
// ❌ 不好的设计
abstract class PoorlyDesignedTemplate {
// 模板方法不是 final,容易被误改
open fun execute() { /* ... */ }
// 抽象方法过多,子类负担重
abstract fun step1(): Data
abstract fun step2(): Data
abstract fun step3(): Data
abstract fun step4(): Data
abstract fun step5(): Data
}
4.3 与策略模式的区别
很多人容易混淆模板方法模式和策略模式,它们的区别在于:
|
方面 |
模板方法模式 |
策略模式 |
|---|---|---|
|
重点 |
算法骨架和流程控制 |
算法实现的互换 |
|
继承关系 |
使用类继承 |
使用对象组合 |
|
运行时 |
编译时确定结构 |
运行时切换算法 |
|
代码复用 |
通过继承复用代码 |
通过组合复用算法 |
// 模板方法模式 - 控制流程
abstract class ReportGenerator {
// 固定生成流程
fun generateReport(): Report {
val data = fetchData() // 抽象方法
val processed = process(data) // 抽象方法
return format(processed) // 具体方法
}
abstract fun fetchData(): Data
abstract fun process(data: Data): ProcessedData
private 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 基类设计
-
业务流程处理器(支付、订单、审批等)
-
框架和库的设计
-
任何有固定流程但不同实现的场景
模板方法模式是构建可维护、可扩展系统的利器。下次当你发现多个类有相似流程时,考虑使用模板方法模式来消除重复,让代码更加优雅!
558

被折叠的 条评论
为什么被折叠?



