SOLID Principles

A class should have only one reason to change, meaning it should only have one responsibility.

// Follows SRP
class UserManager {
    func createUser() {
        // Logic to create user
    }
}

class EmailManager {
    func sendEmail() {
        // Logic to send email
    }
}
                
Classes should be open for extension but closed for modification.

// Follows OCP
protocol Shape {
    func area() -> Double
}

class Rectangle: Shape {
    func area() -> Double {
        return width * height
    }
}

class Circle: Shape {
    func area() -> Double {
        return .pi * radius * radius
    }
}
                
Subtypes should be substitutable for their base types without altering the correctness of the program.

// Follows LSP
class Bird {
    func move() {
        // General movement logic
    }
}

class Penguin: Bird {
    override func move() {
        swim()
    }

    func swim() {
        // Logic for swimming
    }
}
                
No client should be forced to depend on interfaces it does not use.

// Follows ISP
protocol Worker {
    func work()
}

protocol Eater {
    func eat()
}

class Robot: Worker {
    func work() {
        // Robot working logic
    }
}
                
High-level modules should not depend on low-level modules. Both should depend on abstractions.

// Follows DIP
protocol Storage {
    func saveData()
}

class FileStorage: Storage {
    func saveData() {
        // Logic to save data to a file
    }
}

class DataManager {
    let storage: Storage

    init(storage: Storage) {
        self.storage = storage
    }

    func save() {
        storage.saveData()
    }
}