본문 바로가기
OOP/SOLID 원칙

SRP-단일 책임원칙

by Box 2022. 1. 9.
728x90

Single Responsiblity Principle (단일 책임 원칙)

- 하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.

- 클래스를 변경하는 이유는 단 한가지여야 한다.

 

단일 책임 원칙 을 사용하는 이유

설계를 잘한 프로그램은 기본적으로 새로운 요구사항과 프로그램 변경에 영향을 받는 부분이 적다.

다시말해, 응집도는 높고 결합도는 낮은 프로그램을 뜻한다.

만약 한 클래스가 수행할 수 있는 기능, 즉 책임이 많아진다.

책임이 많아지면 클래스 내부의 함수끼리 강한 결합을 발생할 가능성이 높아진다.

이는 유지보수에 비용이 증가하게 되므로 따라서 책임을 분리시킬 필요가 있다.

책임 원칙을 지키지 않으면 특정 기능을 수정할 때 여러 클래스를 수정해야 하는 경우가 생긴다.

단일 책임 원칙을 지키게 되면 유지보수가 편리해진다. 즉, 기능을 변경하기가 쉬워진다.

 

단일 책임 에 대한 오해

1.클래스가 여러가지의 (public) 메소드를 가진다면, 복수의 책임을 갖는가?

2.클래스가 다중상속 (혹은 다중구현)을 한다면, 복수의 책임을 갖는가?

3.해당 클래스를 의존하는 사용자(클라이언트)가 여럿이라면 변경되는 이유는 여러가지가 되는가?

 

SRP는 위와 같은 질문에 단편적으로 답변할 수 없다. 즉, 판단의 기준이 될 수 없는 것이다.

 

‘단일 책임’은 절대적으로 측정할 수 있는 개념이 아니다.

class Employee {
	calculatePay() { ... }
    calculateDeduction() { ... }
    calculateSalary() { ... }
}

하나의 클래스에 메서드가 3개라고 책임이 3개인 것이 아니다.

위 Employee 클래스의 책임은 “Employee에 관련된 정보를 계산하는 것”으로 1개의 책임을 가지고 있는 것이다.

즉, 하나의 책임에 같은 부류의 메서드들이 모여있는 것을 보고 단일 책임 원칙을 지켰다고 얘기하는 것이다.

 

이 의문들을 해결하는 훌륭한 정의가 있습니다.

하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.

액터, 책임의 정의

액터

‘서비스를 사용하는 주체자’의 관점에서 바라보는 것이 중요하다.

이러한 주체자들이 기능의 변경을 요청한다는 뜻이 곧 클래스 변경이 될 것이다.

예를 들면 특정 서비스에 대한 주체자들은 다음과 같다.

  • ‘지속성 모듈’ 서비스 : DBA, 소프트웨어 아키텍터
  • ‘회계’ 서비스 : 점원, 회계사, 운영자
  • ‘급여 시스템의 결제 계산’ 서비스 : 변호사, 관리자, 회계사
  • ‘도서관 관리 시스템’ 서비스 : 사서, 도서관 이용자

이와 같은 서비스를 이용하는 주체자를 ‘액터(actor)’라고 하자.

 

책임

단일 책임 원칙에서 말하는 ‘책임’이란, 하나의 특정 액터(actor)를 위한 기능 집합이다.

 

책임에 대한 변경

액터(actor)가 니즈(사용하고자 하는 기능)가 바뀔 경우, 특정 기능 집합인 클래스의 코드 또한 액터의 니즈에 맞게 바뀌어야만 한다. 

어떤 책임에 대해 액터는 해당 책임에 대해 유일한 변경의 원천이다.

 

액터라는 것을 예시로 들어 자세히 알아 보겠습니다.

예를 들어, '스마트폰'이라는 객체를 철수와 영희가 사용하고 있다고 가정해 봅시다.

이때, 철수는 스마트폰을 영상 시청을 위해서 사용하고 영희는 전화 통화를 위해서 사용합니다.

 

    class 스마트폰 implements 동영상플레이어, 전화 {
        ...
    }

 

첮번째 스마트폰 객체는 철수와 영희가 다른 방식으로 변경되기를 원할 수 있기 때문에 철수와 영희는 별 개의 액터입니다.

두번째 철수가 만약 영상 시청을 위해서 스마트폰의 액정 크기를 변경한다면 전화 통화 요구 사항에는 맞지 않는 변경 사항이 됩니다.

그러므로 해당 스마트폰이 단일 책임 원칙을 지키기 위해서는 다른 액터로 분리되어야 합니다.

 

세번째 철수와 영희가 모두 같은 요구 사항으로 스마트폰을 사용한다면 철수와 영희를 하나로 액터로 볼 수 있으므로 단일 책임 원칙을 준수한다고 할 수 있습니다.

 

이제, 위의 의문점을 해결해 봅시다. 먼저, 두 번째와 세 번째는 액터라는 개념을 통해서 쉽게 해결이 가능합니다.

다중 상속을 받더라도 액터가 그 다중 상속한 것들을 모두 사용한다면 단일 책임 원칙을 만족하는 것이고, 해당 클래스의 사용자가 여러 명이어도 모두 동일한 요구 사항으로 해당 클래스를 사용한다면 단일 책임 원칙을 준수하는 것입니다.

 

첫 번째 의문점도 마찬가지로 서로 다른 액터가 해당 클래스의 여러 가지 메소드를 사용하는 것이 아니라면, 복수의 메소드여도 단일 책임 원칙을 지키고 있는 것입니다.

 

단일 책임 원칙을 지키기 위한 설계 순서

  1. 먼저 요구사항을 분석해 액터를 정의한다.
  2. 각 액터에게 제공해야 할 책임을 파악한다.
  3. 함수와 클래스 각각이 단 하나의 책임만 할당받도록 함수, 클래스를 그룹화한다.

 

 

- 참조- 

'OOP > SOLID 원칙' 카테고리의 다른 글

DIP- 의존역전 원칙  (0) 2022.01.21
ISP- 인터페이스 분리 원칙  (0) 2022.01.21
LSP 리스코프 치환 원칙  (0) 2022.01.19
OCP-개방 폐쇄원칙  (0) 2022.01.19