Swift-SOLID编程原则的实践

SOLID 设计原则概述

SOLID 是 面向对象程序设计中,非常重要的原则,遵循此原则进行编程,意在提高代码的可维护性、可扩展性、可测试性,并减少耦合。

缩写 名称 含义
S Single Responsibility Principle 单一职责
O Open/Closed Principle 开闭原则
L Liskov Substitution Principle 里氏替换
I Interface Segregation Principle 接口隔离
D Dependency Inversion Principle 依赖倒置

单一职责

一个类只负责一项职责。也就是说,一个类应该只有一个引起它变化的原因。

  • 反面教材🚫
swift 复制代码
class UserManager {

    func registerUser(username: String, password: String) {
        // 注册逻辑
        print("注册一个用户: \(username)")
        
        // 发送邮件(这属于另一种职责)
        sendWelcomeEmail(to: username)
    }

    private func sendWelcomeEmail(to username: String) {
        print("发邮件给: \(username)")
    }
}

这里 ,UserManager 同时负责"注册用户"和"发送邮件",职责不单一。另外,发送邮件的业务 原则上只能通过调用sendWelcomeEmail来实现。而这里,调用registerUser也能触发 邮件的发送。不合理。

  • 正确示例✅
swift 复制代码
class UserRegistrationService {
    func register(username: String, password: String) {
        print("User registered: \(username)")
    }
}

class EmailService {
    func sendWelcomeEmail(to username: String) {
        print("Welcome email sent to \(username)")
    }
}

// 使用时
let registrationService = UserRegistrationService()
let emailService = EmailService()
registrationService.register(username: "Tom", password: "123")
emailService.sendWelcomeEmail(to: "Tom")

开闭原则

类、模块、函数应该对扩展开放,对修改关闭。即:不要修改已有代码来适配新需求,而是通过扩展实现。

  • 反面教材🚫
swift 复制代码
class PaymentProcessor {
    func pay(amount: Double, method: String) {
        if method == "wechat" {
            print("微信支付: \(amount)")
        } else if method == "alipay" {
            print("支付宝支付: \(amount)")
        } else {
            print("其他支付")
        }
    }
}

这样写,每新增一种支付方式,都要修改 pay方法。

  • 正确示例✅
swift 复制代码
protocol PaymentMethod {
    func pay(amount: Double)
}

class WeChatPay: PaymentMethod {
    func pay(amount: Double) {
        print("微信支付: \(amount)")
    }
}

class Alipay: PaymentMethod {
    func pay(amount: Double) {
        print("支付宝支付: \(amount)")
    }
}

class PaymentProcessor {
    func process(amount: Double, using method: PaymentMethod) {
        method.pay(amount: amount)
    }
}

// 使用
let processor = PaymentProcessor()
processor.process(amount: 100, using: WeChatPay())
processor.process(amount: 100, using: Alipay())

这样,扩展支付方式时,只需新增类,不改旧代码。

在面向对象编程中,一个类要做什么,考虑扩展需要,最好设计为接口(protocol),而不是直接设计为函数及实现。这也是面向协议编程的思想。

里氏替换

子类必须能够替代父类使用,且不影响程序的正确性。

  • 反面教材🚫
swift 复制代码
class Bird {
    func fly() {
        print("鸟 在飞")
    }
}

class Penguin: Bird {
    override func fly() {
        fatalError("企鹅不能飞")
    }
}

这里, 子类通过重载写自己的业务,但是修改了父类方法实现。这样写代码不好。

  • 正确示例✅
swift 复制代码
protocol Bird {
    func eat()
}

protocol FlyingBird: Bird {
    func fly()
}

class Sparrow: FlyingBird {
    func eat() { print("麻雀 吃") }

    func fly() { print("麻雀 飞") }
}

class Penguin: Bird {
    func eat() { print("企鹅 吃") }
}

通过继承接口,按需得到相应的能力/做需要的事情

协议的继承

接口隔离

不应强迫客户端依赖它不使用的方法。也就是:设计接口 应精简、专一。外界按需继承。

  • 反面教材🚫
swift 复制代码
protocol Worker {
    func work()
    func eat()
}

class Robot: Worker {
    func work() { print("机器人工作") }
    
    func eat() { }   // 不需要
}
  • 正确示例✅
swift 复制代码
protocol Workable {
    func work()
}

protocol Eatable {
    func eat()
}

class Human: Workable, Eatable {
    func work() { print("人 工作") }
    func eat() { print("人 吃饭") }
}

class Robot: Workable {
    func work() { print("机器人工作") }
}

依赖倒置

高层模块不应依赖低层模块,两者都应依赖抽象。换句话说:依赖接口,不依赖实现。(解耦)

  • 反面教材🚫
swift 复制代码
class MySQLDatabase {
    func save(data: String) {
        print("保存到 MySQL: \(data)")
    }
}

class UserManager {
    let db = MySQLDatabase()
    
    func saveUser(name: String) {
        db.save(data: name)
    }
}

这样写,类 UserManager 直接依赖具体数据库实现,耦合严重。

  • 正确示例✅
swift 复制代码
protocol Database {
    func save(data: String)
}

class MySQLDatabase: Database {
    func save(data: String) {
        print("保存到 MySQL: \(data)")
    }
}

class SQLiteDatabase: Database {
    func save(data: String) {
        print("保存到 SQLite: \(data)")
    }
}

class UserRepository {
    private let database: Database
    
    init(database: Database) {
        self.database = database
    }
    
    func saveUser(name: String) {
        database.save(data: name)
    }
}

// 使用时 可自由替换数据库
let repo = UserRepository(database: SQLiteDatabase())
repo.saveUser(name: "Tom")

依赖倒置让代码更易于扩展、测试与切换实现。

通过公共协议 来实现类与类的交互,实现解耦

相关推荐
猪哥帅过吴彦祖4 小时前
Flutter 系列教程:常用基础组件 (下) - `TextField` 和 `Form`
前端·flutter·ios
Digitally15 小时前
从iPhone转移到itel手机的联系人转移指南
ios·智能手机·iphone
Digitally15 小时前
清除 iPhone 数据以便出售:永久删除您的数据
ios·iphone
1024小神1 天前
关于在ios系统中签名并安装ipa文件的五种方法,PakePlus打包的ipa文件可以看看
macos·ios·cocoa
QWQ___qwq1 天前
SwiftUI 的状态管理包装器(Property Wrapper)
ios·swiftui·swift
游戏开发爱好者81 天前
苹果iOS26系统升级:液态玻璃与智能功能全解析
macos·ios·小程序·uni-app·objective-c·cocoa·iphone
心随雨下1 天前
Flutter中新手需要掌握的几种Widget
android·flutter·ios
2501_915918411 天前
iOS 26 App 性能测试|性能评测|iOS 26 性能对比:实战策略
android·macos·ios·小程序·uni-app·cocoa·iphone
namehu2 天前
React Native 应用性能分析与优化不完全指南
android·react native·ios