设计原则SOLID

设计原则SOLID

一、开闭原则

OCP - Open Close Principle

❌下面是一种不好的实现方式,每次改变vip等级都需要修改if-else代码逻辑

struct Vip {
    func service(user: String) {
        if user == "vip1" {
            print("服务vip1: \(user)")
        } else if user == "vip2" {
            print("服务vip2: \(user)")
        }
    }
}

✅下面是符合开闭原则的实现方式,这样每次增删改vip只会处理对应的vip(也可以通过创建基类,子类根据需求不同实现)

protocol ServiceProvider {
    func service(user: String)
}

struct Vip1: ServiceProvider {
    func service(user: String) {
        print("服务vip1: \(user)")
    }
}

struct Vip2: ServiceProvider {
    func service(user: String) {
        print("服务vip2: \(user)")
    }
}

二、单一职责原则

SRP - Single Responsibility Principle

三、里氏替换原则

LSP - Liskov Substitution Principle

四、迪米特法则(最少知道原则)

LoD - Law of Demeter ( Least Knowledge Principle)

五、接口分离原则

ISP - Interface Segregation Principle

protocol Named {
    var name: String { get }
}

protocol Aged {
    var age: Int { get }
}

// 协议组合
struct Man: Named & Aged {
    var name: String
    var age: Int
}

// 也可以重新定义一个名字
typealias Person = Named & Aged

struct Woman: Person {
    var name: String
    var age: Int
}

六、依赖倒置原则

DIP - Dependency Inversion Principle

❌不好的实现方式:高层Mother直接依赖了低层Book,所以只能读书,却不能读报纸了,如果再出现杂志等也是不能读

class Book {
    func getContent() -> String {
        return "很久很久以前有一个故事……";
    }
}

class Newspaper {
    func getContent() -> String {
        return "有一个新闻……";
    }
}

class Mother {
    // 直接依赖低层模块Book,导致无法读报纸Newspaper
    func narrate(book: Book) {
        print("妈妈开始讲故事")
        print(book.getContent())
    }
}

class Client {
    static func run() {
        let mother = Mother();
        mother.narrate(book: Book());
    }
}

✅好的实现:创建接口Contentable,低层依赖接口并实现接口方法,高层Mother通过接口调用低层,很好的实践了依赖倒置,解耦。加入后面再出现杂志,网页等信息,只要添加低层的实现,高层不用变化。

// 创建抽象接口,让低层模块和高层模块都依赖它(面向协议)
protocol Contentable {
    func getContent() -> String
}

// 低层模块也依赖抽象接口Contentable
class Book: Contentable {
    func getContent() -> String {
        return "很久很久以前有一个故事……";
    }
}

class Newspaper: Contentable {
    func getContent() -> String {
        return "有一个新闻……";
    }
}

class Mother {
    // 高层模块Mother依赖抽象接口Contentable,这样如果低层做了修改,高层也是不用改变的
    func narrate(content: Contentable) {
        print("妈妈开始读:")
        print(content.getContent())
    }
}

class Client {
    static func run() {
        let mother = Mother();
        mother.narrate(content: Book());
        mother.narrate(content: Newspaper());
    }
}

参考: