Menu
Menu
Posts List
  1. SOLID 원칙:
    1. SRP - 단일 책임 원칙 (Single Responsibility Principle)
    2. OCP - 개방-폐쇄 원칙 (Open/Closed Principle)
    3. LSP - 리스코프 치환 원칙 (Liskov Substitution Principle)
    4. ISP - 인터페이스 분리 원칙 (Interface Segregation Principle)
    5. DIP - 의존성 역전 원칙 (Dependency Inversion Principle)
    6. 요약

SOLID 원칙

SOLID 원칙:

SOLID는 객체 지향 프로그래밍에서 유지보수성과 확장성을 높이기 위한 다섯 가지 설계 원칙이라고 한다.
Swift에서도 이 원칙들을 적용해 클린하고 유연한 코드 구조를 만드는 방법에 대해서 공부하기위해 포스팅!


SRP - 단일 책임 원칙 (Single Responsibility Principle)

하나의 클래스는 하나의 책임만 가져야 한다.

  • 하나의 객체는 오직 하나의 변화 이유만 가져야 함.
  • 그동안 이 부분은 많이 간과하고 작업을 했었는데.. 조금 더 쪼개면서 책임을 최대한 분리하도록 노력 필요!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ReportDataLoader {
func load() -> ReportData { ... }
}

class PDFFormatter {
func format(data: ReportData) -> PDFFile { ... }
}

class PDFReportGenerator {
let loader = ReportDataLoader()
let formatter = PDFFormatter()

func generateReport() {
let data = loader.load()
let pdf = formatter.format(data: data)
// 파일 저장 등...
}
}

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

확장에는 열려 있고, 변경에는 닫혀 있어야 한다.

  • 기존 코드를 변경하지 않고 새로운 기능을 추가할 수 있어야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ✅ 프로토콜 기반 확장
protocol Payment {
func pay(amount: Double)
}

class CreditCard: Payment {
func pay(amount: Double) { print("Paid via card") }
}

class Paypal: Payment {
func pay(amount: Double) { print("Paid via Paypal") }
}

func processPayment(payment: Payment) {
payment.pay(amount: 100.0)
}

LSP - 리스코프 치환 원칙 (Liskov Substitution Principle)

자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다.

  • 하위 타입은 상위 타입으로 교체해도 프로그램이 깨지지 않아야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal {
func makeSound() {
print("Animal sound")
}
}

class Dog: Animal {
override func makeSound() {
print("Bark")
}
}

func playSound(animal: Animal) {
animal.makeSound() // Dog도 문제없이 사용 가능
}

ISP - 인터페이스 분리 원칙 (Interface Segregation Principle)

클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다.

  • 큰 프로토콜보다는 작은 프로토콜을 여러 개로 나누는 것이 좋음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ❌ 하나의 프로토콜에 모든 기능이 모임
protocol Worker {
func work()
func eat()
}

// ✅ 역할 분리
protocol Workable {
func work()
}

protocol Eatable {
func eat()
}

class Engineer: Workable, Eatable {
func work() { ... }
func eat() { ... }
}

class Robot: Workable {
func work() { ... }
}

DIP - 의존성 역전 원칙 (Dependency Inversion Principle)

상위 모듈은 하위 모듈에 의존하면 안 되고, 둘 다 추상화에 의존해야 한다.

  • 구체적인 구현보다 추상에 의존하게끔 구성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ✅ 프로토콜을 통한 추상화
protocol MessageSender {
func send()
}

class EmailSender: MessageSender {
func send() { print("Send Email") }
}

class NotificationService {
let sender: MessageSender

init(sender: MessageSender) {
self.sender = sender
}

func notify() {
sender.send()
}
}

요약

원칙 설명 Swift 적용 예
SRP 하나의 책임만 가져야 함 UI와 데이터 로직 분리
OCP 기능 확장은 OK, 코드 수정은 NO 프로토콜로 추상화
LSP 자식은 부모를 대체 가능해야 함 상속과 재정의
ISP 인터페이스는 최소 단위로 프로토콜 분리
DIP 추상화에 의존 의존성 주입(DI) 활용