[SOLID] SRP

miori·2022년 11월 6일
0

OOP

목록 보기
1/5
post-thumbnail

SRP (Single Responsibility)

좋은 설계란 기본적으로 시스템에 새로운 요구사항이나 변경이 있을 때 가능한 한 영향 받는 부분을 최소화한 설계이다.
  • 단일책임원칙
  • class 는 단 한개의 책임 즉 기능을 가져야 한다.

왜 여러개 책임을 가지면 안될까?

"변경" 관점에서 이유를 찾을 수 있다.

책임이 많아질수록 서로 다른 역할을 수행하는 코드끼리 강하게 결합될 가능성이 높아지게 되어 시스템이 복잡해질 수 있다. 즉 결합도가 상승하게 되는데 이는 객체지향 설계의 핵심과 거리가 멀다.
그래서 만약 기능에 변경사항이 생기면 이 기능을 사용하는 부분의 코드를 모두 다시 테스트를 해야 할 수도 있다.
또한 결합도가 높기때문에 해당 기능만 수행하는 메서드의 테스트가 힘들어 질수도 있다.

예시 코드 (SRP 위배)

class WorkoutResult {
    func workout() -> String {
        let wods = announce()
        let doWorkout = workout(workouts: wods)
        let result = judge(isDone: doWorkout) ? "오운완" : "노랩천국"
        return result
    }
    private func announce() -> [String] {
        return ["10 Snatch", "10 Burpee"]
    }
    private func workout(workouts: [String]) -> [Bool] {
        return Array(repeating: true, count: workouts.count)
    }
    private func judge(isDone: [Bool]) -> Bool {
        let cnt = isDone.filter { $0 == true }.count
        let judgeResult = cnt == isDone.count ? true : false
        return judgeResult
    }
}

let miori = WorkoutResult()
miori.workout()

위의 코드를 본다면, 클래스 내부에서 서로 다른 기능(역할)을 하는 함수끼리 결합이 되어있다.

만약, 운동을 뭘 할지 알려줄 announce 메서드나 운동을 제대로 수행했는지 확인하는 judge 함수를 바꿔야 한다면 해당클래스에서 계속 수정을 해야한다.
즉 SRP를 위배하게 된다.

따라서 책임을 분리시켜, 한 클래스에서 하나의 책임을 가질 수 있도록 수정해야 OOP가 지향하는 설계에 가까워질수 있다.

예시 코드 (SRP 지켜🚀)

protocol AnnounceProtocol {
    func announce() -> [String]
}

protocol WorkoutProtocol {
    func workout(workouts: [String]) -> [Bool]
}

protocol JudgeProtocol {
    func judge(isDone: [Bool]) -> Bool
}

class SRPWorkoutResult {
    let announce: AnnounceProtocol
    let workouts: WorkoutProtocol
    let judge: JudgeProtocol
    
    func workout() -> String {
        let wods = announce.announce()
        let doWorkout = workouts.workout(workouts: wods)
        let result = judge.judge(isDone: doWorkout) ? "오운완" : "노랩천국"
        return result
    }
    
    init(announce: AnnounceProtocol, workouts: WorkoutProtocol, judge: JudgeProtocol) {
        self.announce = announce
        self.workouts = workouts
        self.judge = judge
    }
}

class Announce: AnnounceProtocol {
    func announce() -> [String] {
        return ["10 Snatch", "10 Burpee"]
    }
}

class Workout: WorkoutProtocol {
    func workout(workouts: [String]) -> [Bool] {
        return Array(repeating: true, count: workouts.count)
    }
}

class Judge: JudgeProtocol {
    func judge(isDone: [Bool]) -> Bool {
        let cnt = isDone.filter { $0 == true }.count
        let judgeResult = cnt == isDone.count ? true : false
        return judgeResult
    }
}

let miori2 = SRPWorkoutResult(announce: Announce(), workouts: Workout(), judge: Judge())
miori2.workout()

위의 코드처럼, 운동을 뭘할지 알려주는 기능 / 운동을 하는 기능 / 운동을 잘하고 있는지 judge를 봐주는 기능 을 나눈다면 결합도는 낮아지게 된다.
그리고 하나의 역할만 하는 기능들끼리 모여있기 때문에 응집도는 높아지게 된다.

profile
iS를 공부하는 miori 입니다.

0개의 댓글