欢迎光临
我们一直在努力

系列一:架构思想进阶 | 第3篇 SOLID 原则与设计模式实战:从“代码搬运工”到“架构师”的必经之路

📱 系列一:架构思想进阶 | 第3篇

SOLID 原则与设计模式实战:从“代码搬运工”到“架构师”的必经之路

本文导读
你是否遇到过这样的情况:改一个登录逻辑,结果把支付模块搞崩了?或者增加一个分享渠道,需要改动十几个文件?
这通常不是代码量的问题,而是设计质量的问题。
本文将带你深入理解 SOLID 五大设计原则,并结合 企业级设计模式实战,教你如何写出像“乐高积木”一样、可插拔、可扩展、可维护的代码。
全文较长,建议配合咖啡阅读,并准备好你的 IDE。


0. 前言:为什么你写的代码总是“牵一发而动全身”?

让我们先看一段真实的“事故现场”代码。

需求:App 需要支持三种登录方式:账号密码、短信验证码、微信登录。

事故代码:

class LoginManager {

fun login(type: Int, username: String, password: String) {
if (type == 1) {
// 账号密码登录
// 校验逻辑…
// 网络请求…
// 保存数据…
} else if (type == 2) {
// 短信登录
// 校验逻辑…
// 网络请求…
// 保存数据…
} else if (type == 3) {
// 微信登录
// 校验逻辑…
// 网络请求…
// 保存数据…
}
}
}

问题来了:

  • 产品经理说:“加一个 Apple 登录”。你需要改动 LoginManager,改 if-else,改测试方法。
  • 测试说:“短信登录有 Bug”。你改了短信逻辑,结果不小心把账号密码登录的逻辑改坏了。
  • 新同事接手:看着这一坨 if-else,不敢动,只能复制粘贴加新逻辑。
  • 这就是“面条代码”的代价。
    要解决这个问题,我们需要 SOLID 原则 和 设计模式。


    1. SOLID 原则:面向对象设计的五根支柱

    SOLID 是 Robert C. Martin(“Bob 大叔”)提出的五大面向对象设计原则。它们是写出好代码的“宪法”。

    1.1 单一职责原则(SRP):一个类只做一件事

    定义:一个类应该只有一个引起它变化的原因。

    通俗解释:别让一个类身兼数职。比如,User 类只负责用户属性,不要把“保存用户到数据库”的逻辑也塞进去。

    反面教材:

    // ❌ 违反 SRP:这个类既管用户属性,又管存储,又管校验
    class User {
    var id: String = ""
    var name: String = ""

    fun saveToDb() { /* 数据库操作 */ }
    fun validatePassword(): Boolean { /* 校验逻辑 */ }
    }

    正面教材:

    // ✅ 符合 SRP:各司其职
    data class User(val id: String, val name: String) // 只管数据

    class UserRepository { // 只管存储
    fun save(user: User) {}
    }

    class UserValidator { // 只管校验
    fun validate(user: User): Boolean {}
    }

    企业级收益:

    • 代码易读:找功能知道去哪个类。
    • 易维护:改存储逻辑不会影响校验逻辑。
    • 易测试:可以单独测试校验逻辑。
    1.2 开闭原则(OCP):对扩展开放,对修改关闭

    定义:软件实体(类、模块、函数)应该对扩展开放,对修改关闭。

    通俗解释:当需求变化时,尽量不要改原来的代码,而是通过新增代码来实现。

    反面教材(就是我们开头的那个):

    // ❌ 违反 OCP:每次加新登录方式,都要改这个类
    class LoginManager {
    fun login(type: Int) {
    if (type == 1) { /* … */ }
    else if (type == 2) { /* … */ }
    }
    }

    正面教材(使用多态):

    // ✅ 符合 OCP:新增登录方式只需新增类,不改现有代码
    interface LoginStrategy {
    fun login()
    }

    class PasswordLogin : LoginStrategy {
    override fun login() { /* 账号密码逻辑 */ }
    }

    class SmsLogin : LoginStrategy {
    override fun login() { /* 短信逻辑 */ }
    }

    class LoginManager(
    private val strategy: LoginStrategy
    ) {
    fun login() {
    strategy.login() // 对修改关闭
    }
    }

    // 使用时
    val manager = LoginManager(PasswordLogin())
    manager.login()
    // 新增微信登录?加一个 WechatLogin 类,LoginManager 一动不动。

    企业级收益:

    • 稳定:老代码不动,就不会引入新 Bug。
    • 灵活:像搭积木一样加功能。
    1.3 里氏替换原则(LSP):子类必须能替换父类

    定义:所有引用基类的地方,必须能透明地使用其子类的对象。

    通俗解释:如果你用父类的地方,换成子类后程序出错了,那就违反了 LSP。

    反面教材:

    open class Bird {
    open fun fly() {}
    }

    class Ostrich : Bird() {
    override fun fly() {
    throw UnsupportedOperationException("鸵鸟不会飞")
    }
    }

    fun letBirdFly(bird: Bird) {
    bird.fly() // 如果是鸵鸟,这里就崩了
    }

    正面教材:

    // 重新设计
    interface Flyable {
    fun fly()
    }

    abstract class Bird

    class Sparrow : Bird(), Flyable {
    override fun fly() { /* 飞 */ }
    }

    class Ostrich : Bird() // 鸵鸟不实现 Flyable

    企业级收益:

    • 避免“假继承”带来的逻辑漏洞。
    • 保证多态的安全性。
    1.4 接口隔离原则(ISP):客户端不应该被迫依赖它不需要的接口

    定义:客户端不应该被迫依赖它不需要的接口。

    通俗解释:别让一个接口胖得像头猪。应该拆成小而专的接口。

    反面教材:

    // ❌ 违反 ISP:一个巨大的接口
    interface Worker {
    fun code()
    fun test()
    fun deploy()
    fun cook() // 厨师也要实现这个?
    }

    class Developer : Worker {
    override fun code() {}
    override fun test() {}
    override fun deploy() {}
    override fun cook() {
    // 我是个开发,我不会做饭,但为了接口不得不空实现
    throw NotImplementedError()
    }
    }

    正面教材:

    // ✅ 符合 ISP:拆分成小接口
    interface Coder {
    fun code()
    }

    interface Tester {
    fun test()
    }

    interface Chef {
    fun cook()
    }

    class Developer : Coder, Tester {
    override fun code() {}
    override fun test() {}
    }

    企业级收益:

    • 接口清晰,实现类不用背负无用的负担。
    • 降低耦合。
    1.5 依赖倒置原则(DIP):面向接口编程,而非实现

    定义:高层模块不应该依赖低层模块,二者都应该依赖抽象。

    通俗解释:别直接 new 具体的实现类,要依赖接口。

    反面教材:

    // ❌ 违反 DIP:高层直接依赖低层实现
    class LoginActivity {
    // 直接依赖具体的实现
    private val repository = UserRepositoryImpl()
    }

    正面教材:

    // ✅ 符合 DIP:依赖抽象
    class LoginActivity(
    private val repository: UserRepository // 依赖接口
    ) {
    // 不管是 Room 还是 Network,只要是 UserRepository 就行
    }

    企业级收益:

    • 可替换:明天换数据库,Activity 不用改。
    • 可测试:Mock 一个假的 Repository 就能测试 Activity。

    2. 设计模式实战:用模式解决具体问题

    设计模式是 SOLID 原则的落地手段。下面我们看几个 Android 开发中最常用的模式。

    2.1 创建型模式:解决“对象怎么来”的问题
    单例模式(Singleton):全局唯一实例

    场景:全局只需要一个实例,比如 NetworkClient、DatabaseManager。

    错误写法(线程不安全):

    object Singleton {
    // Kotlin 的 object 天生是线程安全的单例,推荐用这个
    }

    Java 风格的正确写法(双重校验锁):

    class Singleton private constructor() {
    companion object {
    @Volatile
    private var instance: Singleton? = null

    fun getInstance(): Singleton =
    instance ?: synchronized(this) {
    instance ?: Singleton().also { instance = it }
    }
    }
    }

    企业级建议:

    • 能用 Kotlin object 就用 object。
    • 单例里不要持有 Activity Context(用 Application Context)。
    • 能用 依赖注入(Hilt) 就别手写单例。
    工厂模式(Factory):创建对象的统一入口

    场景:根据条件创建不同的对象(比如不同的 LoginStrategy)。

    class LoginFactory {
    fun create(type: LoginType): LoginStrategy {
    return when (type) {
    LoginType.PASSWORD -> PasswordLogin()
    LoginType.SMS -> SmsLogin()
    LoginType.WECHAT -> WechatLogin()
    }
    }
    }

    企业级建议:

    • ViewModel 的创建必须用 ViewModelProvider.Factory。
    • 复杂对象的创建用工厂,别在 Activity 里直接 new。
    建造者模式(Builder):复杂对象的构建

    场景:创建一个对象需要很多参数,且参数可选。

    经典案例:AlertDialog.Builder

    val dialog = AlertDialog.Builder(this)
    .setTitle("提示")
    .setMessage("确定删除?")
    .setPositiveButton("确定") { _, _ -> }
    .setNegativeButton("取消") { _, _ -> }
    .create()

    自定义 Builder:

    class RequestConfig private constructor(
    val url: String,
    val timeout: Int,
    val retryCount: Int
    ) {
    class Builder {
    private var url: String = ""
    private var timeout: Int = 30
    private var retryCount: Int = 3

    fun url(url: String) = apply { this.url = url }
    fun timeout(timeout: Int) = apply { this.timeout = timeout }
    fun build() = RequestConfig(url, timeout, retryCount)
    }
    }

    // 使用
    val config = RequestConfig.Builder()
    .url("https://api.xxx.com")
    .timeout(60)
    .build()

    2.2 结构型模式:解决“类和对象怎么组合”的问题
    适配器模式(Adapter):让不兼容的接口一起工作

    场景:对接第三方 SDK,或者 RecyclerView 的 Adapter。

    RecyclerView 示例:

    class UserAdapter : RecyclerView.Adapter<UserAdapter.ViewHolder>() {

    private val userList = mutableListOf<User>()

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    // 把 User 适配成 View
    holder.bind(userList[position])
    }
    }

    对接 SDK 示例:

    // 旧 SDK
    class OldPaySdk {
    fun doPay(money: Int) {}
    }

    // 新 App 需要的接口
    interface NewPayApi {
    fun pay(amount: Double)
    }

    // 适配器
    class PayAdapter(private val oldSdk: OldPaySdk) : NewPayApi {
    override fun pay(amount: Double) {
    oldSdk.doPay(amount.toInt()) // 适配转换
    }
    }

    装饰器模式(Decorator):动态添加功能

    场景:给网络请求加日志、缓存、重试。

    interface HttpClient {
    fun request(url: String): String
    }

    class BaseHttpClient : HttpClient {
    override fun request(url: String): String {
    return "Response from $url"
    }
    }

    // 装饰器:加日志
    class LoggingDecorator(private val client: HttpClient) : HttpClient {
    override fun request(url: String): String {
    println("Requesting: $url")
    return client.request(url)
    }
    }

    // 使用
    val client = LoggingDecorator(BaseHttpClient())
    client.request("https://api.xxx.com")

    外观模式(Facade):简化复杂子系统

    场景:App 启动时需要初始化一堆 SDK。

    不用 Facade(Activity 里乱成一团):

    class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    UMengManager.init(this)
    BuglyManager.init(this)
    PushManager.init(this)
    // … 还有 10 个
    }
    }

    用 Facade(一键初始化):

    object AppInitializer {
    fun init(context: Context) {
    initUMeng(context)
    initBugly(context)
    initPush(context)
    }
    }

    // Activity 里
    AppInitializer.init(this)

    2.3 行为型模式:解决“对象之间怎么通信”的问题
    观察者模式(Observer):事件订阅与通知

    场景:LiveData、RxJava、Flow 都是观察者模式。

    自定义实现:

    class EventBus {
    private val listeners = mutableMapOf<Class<*>, MutableList<(Any) -> Unit>>()

    fun <T : Any> subscribe(eventType: Class<T>, action: (T) -> Unit) {
    listeners.getOrPut(eventType) { mutableListOf() }.add(action as (Any) -> Unit)
    }

    fun post(event: Any) {
    listeners[event::class.java]?.forEach { it.invoke(event) }
    }
    }

    // 使用
    EventBus.subscribe(LoginEvent::class.java) { event ->
    println("User logged in: ${event.userId}")
    }

    策略模式(Strategy):替换复杂的 if-else

    场景:支付方式、分享渠道、排序算法。

    这是我们开头解决的问题。通过 LoginStrategy 接口,消除了 if-else。

    责任链模式(Chain of Responsibility):请求的处理链

    场景:登录前的校验链(检查网络、检查 Token、检查权限)。

    abstract class Interceptor {
    protected var next: Interceptor? = null
    fun setNext(next: Interceptor): Interceptor {
    this.next = next
    return next
    }
    abstract fun intercept(request: LoginRequest): LoginResult
    }

    class NetworkInterceptor : Interceptor() {
    override fun intercept(request: LoginRequest): LoginResult {
    if (!hasNetwork()) return LoginResult.Error("No network")
    return next?.intercept(request) ?: LoginResult.Success
    }
    }

    // 组装链条
    val chain = NetworkInterceptor()
    chain.setNext(TokenInterceptor())
    .setNext(PermissionInterceptor())
    .setNext(RealLoginInterceptor())

    状态模式(State):对象状态的行为变化

    场景:订单状态(待支付、已支付、已发货、已完成)。

    interface OrderState {
    fun pay()
    fun ship()
    }

    class PendingState : OrderState {
    override fun pay() { println("Paid") }
    override fun ship() { println("Cannot ship, not paid") }
    }

    class PaidState : OrderState {
    override fun pay() { println("Already paid") }
    override fun ship() { println("Shipped") }
    }

    class Order(var state: OrderState) {
    fun pay() = state.pay()
    fun ship() = state.ship()
    }


    3. 企业级实战:登录模块的重构之路

    现在,让我们用 SOLID + 设计模式 重构开头的那个“事故代码”。

    3.1 重构目标
  • 消除 if-else。
  • 新增登录方式不修改旧代码。
  • 各模块职责单一。
  • 3.2 重构后的架构

    #mermaid-svg-LW7EOlIhnoEQ7lv3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .error-icon{fill:#552222;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .marker.cross{stroke:#333333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 p{margin:0;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .cluster-label text{fill:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .cluster-label span{color:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .cluster-label span p{background-color:transparent;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .label text,#mermaid-svg-LW7EOlIhnoEQ7lv3 span{fill:#333;color:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .node rect,#mermaid-svg-LW7EOlIhnoEQ7lv3 .node circle,#mermaid-svg-LW7EOlIhnoEQ7lv3 .node ellipse,#mermaid-svg-LW7EOlIhnoEQ7lv3 .node polygon,#mermaid-svg-LW7EOlIhnoEQ7lv3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .rough-node .label text,#mermaid-svg-LW7EOlIhnoEQ7lv3 .node .label text,#mermaid-svg-LW7EOlIhnoEQ7lv3 .image-shape .label,#mermaid-svg-LW7EOlIhnoEQ7lv3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .rough-node .label,#mermaid-svg-LW7EOlIhnoEQ7lv3 .node .label,#mermaid-svg-LW7EOlIhnoEQ7lv3 .image-shape .label,#mermaid-svg-LW7EOlIhnoEQ7lv3 .icon-shape .label{text-align:center;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .node.clickable{cursor:pointer;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .arrowheadPath{fill:#333333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LW7EOlIhnoEQ7lv3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LW7EOlIhnoEQ7lv3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LW7EOlIhnoEQ7lv3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .cluster text{fill:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .cluster span{color:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LW7EOlIhnoEQ7lv3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .icon-shape,#mermaid-svg-LW7EOlIhnoEQ7lv3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .icon-shape p,#mermaid-svg-LW7EOlIhnoEQ7lv3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .icon-shape rect,#mermaid-svg-LW7EOlIhnoEQ7lv3 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LW7EOlIhnoEQ7lv3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LW7EOlIhnoEQ7lv3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LW7EOlIhnoEQ7lv3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Data

    Domain

    UI

    调用

    依赖抽象

    实现

    实现

    实现

    LoginActivity

    LoginUseCase

    LoginStrategy

    PasswordLoginStrategy

    SmsLoginStrategy

    WechatLoginStrategy

    3.3 代码实现

    1. 定义策略接口(DIP + OCP)

    interface LoginStrategy {
    suspend fun login(credentials: Map<String, String>): Result<Boolean>
    }

    2. 实现具体策略(SRP)

    class PasswordLoginStrategy : LoginStrategy {
    override suspend fun login(credentials: Map<String, String>): Result<Boolean> {
    val username = credentials["username"] ?: return Result.failure(Exception("No username"))
    val password = credentials["password"] ?: return Result.failure(Exception("No password"))
    // 调用网络…
    return Result.success(true)
    }
    }

    class SmsLoginStrategy : LoginStrategy {
    override suspend fun login(credentials: Map<String, String>): Result<Boolean> {
    // 短信逻辑…
    return Result.success(true)
    }
    }

    3. 工厂创建策略(Factory)

    class LoginStrategyFactory {
    fun create(type: LoginType): LoginStrategy {
    return when (type) {
    LoginType.PASSWORD -> PasswordLoginStrategy()
    LoginType.SMS -> SmsLoginStrategy()
    }
    }
    }

    4. UseCase 编排(Facade + SRP)

    class LoginUseCase(
    private val strategyFactory: LoginStrategyFactory
    ) {
    suspend fun execute(type: LoginType, credentials: Map<String, String>): Result<Boolean> {
    val strategy = strategyFactory.create(type)
    return strategy.login(credentials)
    }
    }

    5. ViewModel 调用(MVVM)

    @HiltViewModel
    class LoginViewModel @Inject constructor(
    private val loginUseCase: LoginUseCase
    ) : ViewModel() {

    private val _state = MutableStateFlow(LoginUiState())
    val state = _state.asStateFlow()

    fun login(type: LoginType, credentials: Map<String, String>) {
    viewModelScope.launch {
    _state.update { it.copy(isLoading = true) }
    val result = loginUseCase.execute(type, credentials)
    _state.update { it.copy(isLoading = false, success = result.isSuccess) }
    }
    }
    }

    6. Activity 只负责 UI(Presentation Layer)

    class LoginActivity : AppCompatActivity() {
    private val viewModel: LoginViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 点击密码登录
    binding.btnPasswordLogin.setOnClickListener {
    viewModel.login(
    LoginType.PASSWORD,
    mapOf("username" to "xxx", "password" to "xxx")
    )
    }
    // 点击短信登录
    binding.btnSmsLogin.setOnClickListener {
    viewModel.login(
    LoginType.SMS,
    mapOf("phone" to "13800138000")
    )
    }
    }
    }

    3.4 重构收益对比
    指标重构前重构后
    新增微信登录 改 LoginManager,加 if-else 新增 WechatLoginStrategy 类,不动任何老代码
    测试 需要启动 App 测试 可以直接测试 PasswordLoginStrategy
    维护 牵一发而动全身 只改对应的 Strategy
    代码量 一个类几百行 每个类几十行,清晰

    4. 总结与检查清单

    4.1 什么时候用设计模式?

    不要为了用模式而用模式。只有当你的代码出现以下症状时,才考虑模式:

    • 症状 1:if-else / switch 超过 3 层。
    • 症状 2:一个类超过 300 行,且职责混乱。
    • 症状 3:修改一个功能会影响其他功能。
    4.2 企业级检查清单

    在项目 Code Review 时,请对照这份清单:

    SOLID 检查:

    • 类是否只有一个职责?(SRP)
    • 新增功能是否主要靠新增类,而不是改老类?(OCP)
    • 子类是否能无缝替换父类?(LSP)
    • 接口是否小而专?(ISP)
    • 是否依赖抽象接口,而不是具体实现?(DIP)

    设计模式检查:

    • 对象创建是否用了工厂/建造者?
    • 复杂初始化是否用了外观模式?
    • 消除 if-else 是否用了策略模式?
    • 请求预处理是否用了责任链?
    • 状态变化是否用了状态模式?

    下期预告:
    系列二:MVVM 深度实战与项目重构 | 第4篇:组件化架构从零搭建实战
    (我们将跳出单工程,开始拆分子模块,解决“编译慢、代码冲突、业务耦合”的终极难题。)


    如果这篇文章帮你理清了思路,请分享给你的队友。毕竟,架构不是一个人的事,而是一群人的共识。

    赞(0)
    未经允许不得转载:171主机测评 » 系列一:架构思想进阶 | 第3篇 SOLID 原则与设计模式实战:从“代码搬运工”到“架构师”的必经之路
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址