LostCatBox

단일책임원칙이란?

Word count: 525Reading time: 3 min
2024/04/21 Share

왜?

  • SOLID 원칙 중에 하나
  • 면접에서 설계도를 리뷰하며, 단일 책임 원칙에 따라 기존 코드가 어떻게 변경되어야하는지 정확히 대답하지 못했다.
  • 따라서 예시를 통해 재학습하기로 결정했다.

참고

단일 책임 원칙이란?

  • 하나의 클래스로 너무 많은 일을 하지 말고 딱 한 가지 책임만 수행하라는 뜻이다
  • 변경 사항이 일어났을 경우, 단일책임원칙을 지켰다면, 하나 클래스 내용만 변경될 것이다.

잘못된 예시

  • 회계팀, 인사팀, 기술팀이 사용하는 메서드는 모두 calulateExtraHour() 에 의존적이다.

  • 만약 인사팀에서 해당 로직을 변경되어야 할경우 의도치 않은 나머지 2개의 팀을 모두 검증해야할 필요가 생긴다.

  • 이유는 Employee 클래스에서 회계팀, 인사팀, 기술팀 이렇게 3개의 액터에 대한 책임을 한꺼번에 갖고있기 때문이다.

    1
    2
    액터는 시스템을 수행하는 역할을 하는 요소로써, 시스템을 이용하는 사용자, 하드웨어 혹은 외부 시스템이 될 수 있다.
    회계팀, 인사팀, 기술팀에서 데이터를 얻기위해 하나의 Employee 클래스를 사용하기 때문에, 3개의 액터가 하나의 클래스를 변경할 수 있는 요인이 되어 SRP 원칙을 어긴 구조라고 하는 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
@Id
@GeneratedValue
private int id;
private String name;
private int age;
private String address;

public static Employee create(EmployeeAddRequest request) {
return Employee.builder()
.name(request.getName())
.age(request.getAge())
.address(request.getAddress())
.build();
}

public void calulateExtraHour(){
System.out.println("초과 근무 시간 계산 메서드(두 팀이 모두 공유)");
}

public void calulatePay() {
this.calulateExtraHour();
System.out.println("회계팀 사용하는 초과 근무 시간에 따른 급여 메서드");
}

public void reportHours(){
this.calulateExtraHour();
System.out.println("인사팀에서 사용하는 초과 근무 시간에 따른 인사평가 자료 추출 메서드");
}

public void saveDB(){
this.calulateExtraHour();
System.out.println("기술 팀에서 사용하는 초과 근무 시간 기록용 메서드");
}
}

단일 책임 원칙 적용 코드

  • 각자의 caculaterExtraHour() 메서드를 갖고, 외부액터에서 이용시 퍼사드 패턴 적용된 객체만 바라보면된다.
  • 해당 구조로 작성된다면, 만약 인사팀에서 해당 로직을 변경되어야 할경우 HourReport.reportHours() 만 변경하면된다. 영향도없음

구조도

스크린샷 2024-04-21 오후 1.03.05

EmployeeFacade

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@AllArgsConstructor
@NoArgsConstructor
public class EmployeeFacade {
private int id;
private String name;
private int age;
private String address;

public void calulatePay() {
new PayCalculator().calulatePay();
}

public void reportHours() {
new HourReport().reportHours();
}

public void saveDb(){
new EmploySaver().saveDB();
}
}

EmploySaver, HourReport, PayCalculator

  • EmploySaver
1
2
3
4
5
6
7
8
9
10
11
12
public class EmploySaver {


private void calulateExtraHour(){
System.out.println("초과 근무 시간 계산 메서드(기술팀만 사용)");
}

public void saveDB(){
calulateExtraHour();
System.out.println("기술 팀에서 사용하는 초과 근무 시간 기록용 메서드");
}
}
  • HourReport
1
2
3
4
5
6
7
8
9
10
11
12
13
public class HourReport {

private void calulateExtraHour(){
System.out.println("초과 근무 시간 계산 메서드(인사팀만 사용)");
}

public void reportHours(){
calulateExtraHour();
System.out.println("인사팀에서 사용하는 초과 근무 시간에 따른 인사평가 자료 추출 메서드");
}


}
  • PayCaculator
1
2
3
4
5
6
7
8
9
10
public class PayCalculator {
private void calulateExtraHour(){
System.out.println("초과 근무 시간 계산 메서드(회계팀만 사용)");
}

public void calulatePay() {
calulateExtraHour();
System.out.println("회계팀 사용하는 초과 근무 시간에 따른 급여 메서드");
}
}

SRP 원칙 적용 주의점

클래스명은 책임의 소재를 알수있게 작명

  • 어떠한 기능을 담당하는지 명료하게

책임을 분리할때 항상 응집도는 높게, 결합도는 낮은 방향으로 설계

  • 응집도는 한 프로그램 요소가 얼마나 뭉쳐있는가에 대한 척도
  • 결합도는 프로그램 구성 요소들 간의 의존성을 나타냄

산탄총 수술

  • 하나의 책임 담당이 여러 개의 클래스들로 분산되어있는경우, SRP에 입각해 설계변경해야한다
  • 여러개의 모듈에서 자체적으로 로깅, 보안, 트랜잭션을 처리하고 있는데, 아무리 로깅과 같은 사소하고 부가적인 기능이라도 여러 모듈에 공통적으로 자주 이용된다면 책임 소지를 분리해 따로 클래스로 관리하라는 뜻이다.

스크린샷 2024-04-21 오후 1.36.10

CATALOG
  1. 1. 왜?
  2. 2. 참고
  3. 3. 단일 책임 원칙이란?
  4. 4. 잘못된 예시
  5. 5. 단일 책임 원칙 적용 코드
    1. 5.1. 구조도
    2. 5.2. EmployeeFacade
    3. 5.3. EmploySaver, HourReport, PayCalculator
  6. 6. SRP 원칙 적용 주의점
    1. 6.1. 클래스명은 책임의 소재를 알수있게 작명
    2. 6.2. 책임을 분리할때 항상 응집도는 높게, 결합도는 낮은 방향으로 설계
    3. 6.3. 산탄총 수술