LostCatBox

단일책임원칙이란?

Word count: 525Reading time: 3 min
2024/04/21 7 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. 단일 책임 원칙 적용 코드
  6. 6. SRP 원칙 적용 주의점