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

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

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

相关推荐
游戏开发爱好者82 小时前
日常开发与测试的 App 测试方法、查看设备状态、实时日志、应用数据
android·ios·小程序·https·uni-app·iphone·webview
黑码哥2 小时前
ViewHolder设计模式深度剖析:iOS开发者掌握Android列表性能优化的实战指南
android·ios·性能优化·跨平台开发·viewholder
2501_915106324 小时前
app 上架过程,安装包准备、证书与描述文件管理、安装测试、上传
android·ios·小程序·https·uni-app·iphone·webview
2501_915106324 小时前
使用 Sniffmaster TCP 抓包和 Wireshark 网络分析
网络协议·tcp/ip·ios·小程序·uni-app·wireshark·iphone
熊猫钓鱼>_>4 小时前
移动端开发技术选型报告:三足鼎立时代的开发者指南(2026年2月)
android·人工智能·ios·app·鸿蒙·cpu·移动端
徐同保1 天前
通过ip访问nginx的服务时,被第一个server重定向了,通过设置default_server解决这个问题
ios·iphone
2501_915918411 天前
在 iOS 环境下查看 App 详细信息与文件目录
android·ios·小程序·https·uni-app·iphone·webview
2501_916007471 天前
没有 Mac 用户如何上架 App Store,IPA生成、证书与描述文件管理、跨平台上传
android·macos·ios·小程序·uni-app·iphone·webview
夏幻灵2 天前
HTTPS全面解析:原理、加密机制与证书体
ios·iphone
TheNextByte12 天前
如何在iPhone上恢复已删除的笔记的综合指南
笔记·ios·iphone