前言:
很多架构在项目初的时候看不出破绽;只有当项目维护和扩展越来越难的时候,才真正意识到——设计模式不是“装饰”,而是“地基” 。
背景起点:一个日常刷新操作的尴尬实现
abstract class BaseCustomView : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
protected abstract fun onRefreshView()
}
❗问题显现:灵活性的代价是“失控”
子类实现onRefreshViwe的具体业务逻辑,表面看这没有问题,但随着项目复杂度提升,我发现:
- 想要在刷新时加个节流逻辑或埋点日志,无处下手;
- 子类多了之后,每个子类都要手动调用通用逻辑,非常容易遗漏;
- 所有子类行为无法被基类掌控,流程难以统一。
深层剖析:违反了哪些设计原则?
这样的设计,很明显违背了设计模式中的若干设计原则
从单一职责原则触发,即:
- onRefreshViwe() 既承担了“触发刷新逻辑”的职责,又承担了“执行刷新内容”的职责;
- 结果导致:无法单独插入通用逻辑,也无法明确区分“框架控制流程”和“具体视图变化”;
- 日后代码越来越多,难以维护、测试、复用。
从开闭原则出发,即:
- 如果想增加通用刷新逻辑(比如打点、节流、动画),只能:
-
- 修改所有子类 onRefreshViwe();
-
- 或者要求外部每次调用 onRefreshViwe() 前都记得手动调用某个逻辑;
- 这相当于每次“扩展”都需要“修改”已有逻辑,违反了开闭原则。
从控制反转确实出发,即
- onRefreshViwe() 由子类和调用方直接控制,基类失去了调度权;
- 想在不破坏现有代码的前提下“统一流程”,几乎不可能;
- 外部代码直接操作了本该由框架控制的生命周期,导致后期可插拔、扩展困难。
✅ 解决之道:模板方法模式的回归
abstract class BaseCustomView : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
/**
* 外部调用的统一入口,包含基础逻辑
*/
final fun refreshView() {
// 基类统一逻辑
invalidate() // 或其他通用刷新逻辑
// 调用子类的实际逻辑
onRefreshView()
}
/**
* 子类重写这个方法,而不是原来的 onRefreshView()
*/
protected abstract fun onRefreshView()
}
优化后方案统一入口,控制权回归基类,子类只关注差异逻辑,提升维护性与可控性。
设计让流程控制权下放给了子类和外部,牺牲了封装性和扩展性,导致架构可控性差、通用逻辑难以集中、维护代价高。
这其实是一个很小的项目架构的问题,在日常的工作会出现无数的这样的问题,解决方法也不只是我说的那样,如果不嫌麻烦,单独处理所有子类也是一种处理的技术手段,技术手段服务于项目这没毛病,只是更好的架构能节省更多的时间和精力。
为什么设计模式“知道却用不上”?
设计模式在初期看起来“多余”
- 项目刚开始、逻辑简单,直接写 if、new 这些快速完成需求就好。
- 工期紧、团队初始,复杂结构反而让人觉得“多此一举”。
但问题是,不是设计模式太复杂,而是项目现在太简单 —— 一旦复杂度上来,设计失控的代价就暴露了。 写起来“方便”的做法,往往是“技术债”起点
- 直接 override 方法、直接调用子类方法,省了写接口、抽象类、模板方法;
- 但这些方便背后的成本是:缺乏抽象、耦合加深、流程不可控; 日后需求变更或新增功能时,才发现所有逻辑“黏”在一起,动一个地方就像抽积木。
类似场景下的设计模式选型参考
| 场景 | 痛点 | 推荐模式 | 作用 |
|---|---|---|---|
| View 刷新流程不统一 | 控制权分散 | 模板方法模式 | 统一入口,流程可控 |
| 同一功能多种变化 | 逻辑难以复用 | 策略模式 | 可切换刷新策略 |
| 初始化参数复杂 | 构造混乱 | 建造者模式 | 解耦构造与表现 |
| 多模块状态通知 | 回调混乱 | 观察者模式 | 解耦通知与响应方 |
| 复杂条件处理 | if-else 增长 | 状态模式 / 责任链 | 流程可扩展,职责清晰 |
结语:项目在成长,架构必须进化
设计模式不是“高级标签”,而是降低维护成本、统一团队协作的结构基础。
附:设计模式六大原则简表
| 原则 | 核心思想 | 对应优化点 |
|---|---|---|
| 单一职责原则(SRP) | 一个类只负责一项职责 | 降低类复杂度 |
| 开闭原则(OCP) | 对扩展开放,对修改关闭 | 支持灵活扩展 |
| 里氏替换原则(LSP) | 子类能替代父类使用 | 提升继承可靠性 |
| 依赖倒置原则(DIP) | 依赖抽象而非细节 | 降低模块耦合 |
| 接口隔离原则(ISP) | 接口尽量小而专一 | 提高接口清晰度 |
| 迪米特法则(LoD) | 最少知道原则 | 降低对象之间的耦合 |