[TIL] 객체지향 solid 원칙

Eden·2025년 9월 10일

객체지향 프로그래밍(OOP)에서 좋은 설계를 위해 지켜야 하는 대표적인 5가지 원칙을 SOLID라고 부릅니다.
Swift로 예시를 들어 이해하기 쉽게 정리했습니다.


1. SRP (Single Responsibility Principle, 단일 책임 원칙)

  • 하나의 클래스는 하나의 책임만 가져야 한다.
  • 변경 사유가 오직 하나여야 한다.
// 잘못된 예시: User가 여러 책임을 가짐
class User {
    func login() { }
    func saveLog() { }
    func sendNotification() { }
}

// 올바른 예시: 역할 분리
class UserAuth {
    func login() { }
}

class UserLogger {
    func saveLog() { }
}

class UserNotifier {
    func sendNotification() { }
}

2. OCP (Open/Closed Principle, 개방-폐쇄 원칙)

  • 확장에는 열려 있고, 변경에는 닫혀 있어야 한다.
protocol Shape {
    func area() -> Double
}

class Circle: Shape {
    let radius: Double
    init(radius: Double) { self.radius = radius }
    func area() -> Double { return Double.pi * radius * radius }
}

class Rectangle: Shape {
    let width: Double
    let height: Double
    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }
    func area() -> Double { return width * height }
}

새로운 도형을 추가해도 기존 코드를 수정할 필요가 없다.


3. LSP (Liskov Substitution Principle, 리스코프 치환 원칙)

  • 자식 클래스는 부모 클래스의 행동을 대체할 수 있어야 한다.
class Bird {
    func fly() { print("I can fly") }
}

class Penguin: Bird {
    // LSP 위반: 펭귄은 날 수 없음
    override func fly() { fatalError("펭귄은 날 수 없습니다.") }
}

→ Penguin은 Bird로 대체 불가능하므로 잘못된 설계.
부모 클래스에 공통 기능만 넣고, 자식은 적절히 확장해야 한다.


4. ISP (Interface Segregation Principle, 인터페이스 분리 원칙)

  • 클라이언트는 자신이 사용하지 않는 메서드에 의존하면 안 된다.
// 잘못된 예시
protocol Worker {
    func work()
    func eat()
    func sleep()
}

// 로봇은 eat, sleep 불필요 → 불필요한 의존 발생
class Robot: Worker {
    func work() { print("Working") }
    func eat() { } // 필요 없음
    func sleep() { } // 필요 없음
}

// 올바른 예시: 인터페이스 분리
protocol Workable { func work() }
protocol Eatable { func eat() }
protocol Sleepable { func sleep() }

class Human: Workable, Eatable, Sleepable {
    func work() { }
    func eat() { }
    func sleep() { }
}

class RobotV2: Workable {
    func work() { }
}

5. DIP (Dependency Inversion Principle, 의존 역전 원칙)

  • 고수준 모듈은 저수준 모듈에 의존하지 말아야 한다.
  • 둘 다 추상화에 의존해야 한다.
protocol InputDevice {
    func input() -> String
}

class Keyboard: InputDevice {
    func input() -> String { return "키보드 입력" }
}

class Mouse: InputDevice {
    func input() -> String { return "마우스 입력" }
}

class Computer {
    private let device: InputDevice
    init(device: InputDevice) {
        self.device = device
    }
    func start() {
        print("입력 장치: \(device.input())")
    }
}

// 사용 예시
let computer = Computer(device: Keyboard())
computer.start()

정리

  • SRP: 클래스는 하나의 책임만 가져라
  • OCP: 확장에는 열려 있고 변경에는 닫혀라
  • LSP: 자식은 부모를 대체할 수 있어야 한다
  • ISP: 사용하지 않는 메서드에 의존하지 마라
  • DIP: 추상화에 의존하라

Swift에서도 SOLID 원칙을 따르면 코드가 읽기 쉽고, 유지보수 및 확장이 용이한 구조를 만들 수 있다.

profile
iOS Dev

0개의 댓글