模板方法模式:优雅地封装算法骨架

在软件设计中,我们经常遇到这样的场景:多个类有相同的算法流程,但某些步骤的具体实现各不相同。模板方法模式通过定义算法骨架、延迟具体实现,完美解决了代码重复和流程控制问题。

一、真实案例:支付流程的烦恼

想象一下,你正在开发一个电商应用,需要接入多种支付方式:

// ❌ 重复的支付流程代码
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 模式结构

模板方法模式包含两个核心部分:

  1. 抽象模板类​:定义算法骨架

  2. 具体实现类​:实现特定步骤

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)
    }
}

六、总结

模板方法模式通过"好莱坞原则"(不要调用我们,我们会调用你)实现了:

  1. 代码复用​ - 将通用算法逻辑提升到父类

  2. 流程控制​ - 确保算法执行顺序一致性

  3. 扩展灵活​ - 通过钩子方法支持未来扩展

  4. 维护简单​ - 修改算法只需修改父类

适用场景:​

  • Android Activity/Fragment 基类设计

  • 业务流程处理器(支付、订单、审批等)

  • 框架和库的设计

  • 任何有固定流程但不同实现的场景

模板方法模式是构建可维护、可扩展系统的利器。下次当你发现多个类有相似流程时,考虑使用模板方法模式来消除重复,让代码更加优雅!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值