Posts 객체 지향 언어의 특징 - 기능과 책임 분리
Post
Cancel

객체 지향 언어의 특징 - 기능과 책임 분리

해당 글은 최범균 님의 객체 지향 프로그래밍 입문 강의를 듣고 정리한 내용입니다.

기능


  • 기능은 하위 기능으로 분해 가능하다
    • 각각의 기능을 누가 제공할 것인지 결정하는 것이 객체 지향 설계의 기본이다.
  • 기능은 곧 책임이다.
    • 따라서, 분리한 기능을 알맞게 분배해야한다.(책임 분리)

image

  • 분리한 하위 기능을 활용해서 전체 기능을 완성한다.
    1
    2
    3
    4
    5
    6
    7
    8
    
    public class ChangePasswordService {
      public Result changePassword(...) {
          Member findMem = memberRepository.findById(id);
          if(findMem==null)
    
          ...
      }
    }
    

기능을 분리하지 않으면 ?

  • 클래스나 메서드가 커지면 절차 지향의 문제가 발생한다.
    • 큰 클래스의 경우 많은 필드를 많은 메서드가 공유하게 된다.
    • 큰 메서드의 경우 많은 변수를 많은 코드가 공유하게 된다.
    • 이런 경우, 여러 기능이 한 클래스/메서드에 섞여 있을 가능성이 높다.
  • 따라서, 책임에 따라 코드를 적절하게 분리해야 한다.

책임 분배/분리 방법 살펴보기


크게 ‘패턴 적용’, ‘계산 기능 분리’, ‘외부 연동 분리’, ‘조건별 분기 추상화’ 관점에서 분리해 볼 수 있다.

1. 패턴 적용(전형적인 역할 분리)

  • 간단한 웹 - 컨트롤러, 서비스, DAO
  • 복잡한 도메인 - 엔티티, VO, 리파지토리, 도메인 서비스
  • AOP - Aspect(공통 기능)
  • 디자인 패턴 - 팩토리, 빌더, 전략, 템플릿 메서드 등

2. 계산 기능 분리

Before

1
2
3
4
5
6
7
8
9
10
11
12
13
Member mem = memberRepository.findOne(id);
Product prod = productRepository.findOne(prodId);

int payAmount = prod.getPrice() * orderReq.getAmount();
double pointRate = 0.01;

if(mem.getMembership() == GOLD) {
    계산 ...
} else if(mem.getMembership() == SILVER) {
    계산 ...
}
...

After

포인트 계산에 대한 책임은 PointCalculator에게 맡긴다. 이를 통해, 포인트 계산에 대한 부분만 따로 테스트 할 수 있게된다. 즉, 역할 분리가 잘 되면 테스트가 용이해지는 장점도 얻을 수 있다.

1
2
3
4
5
6
7
8
9
Member mem = memberRepository.findOne(id);
Product prod = productRepository.findOne(prodId);

int payAmount = prod.getPrice() * orderReq.getAmount();
PointCalculator cal = new PointCalculator(...);

int point = cal.calculate();
...

1
2
3
4
5
6
7
8
9
public class PointCalculator {
    ...
    public int calculate() {
      if(membership == GOLD) {
        ...
      }
        ...
    }
}

3. 외부 연동 분리

네트워크, 메시징, 파일 등에 대한 연동 코드를 분리한다.

Before

1
2
3
4
Product prod = findOne(id);

RestTemplate rest = new RestTemplate();
List<RecommendItem> recoItems = rest.get("http:// ~~?prodId="+ prod.getId());

After

의도가 잘 드러나는 이름을 사용하도록 신경쓰자. 위와 같은 상황에서는
HttpDataService 보다 RecommendService가 더 직관적일 것이다.

1
2
3
4
Product prod = findOne(id);

RecommendService recoService = new RecommendService();
List<RecommendItem> recoItems = recoService.getRecommendItems(prod);

4. 조건별 분기 추상화

조건별 분기가 산재해 있는 경우, 추상화 할 수 있는(공통적으로 묶을 수 있는) 부분이 있는지 살펴본다.

Before

1
2
3
4
5
6
7
8
String fileUrl = "";
if(fildId.startWith(...)) {
    fileUrl = ...;
} else if(fileId.startWith(...)) {
    fileUrl = ...;
} else if(...) {
    fileUrl = ...;
}

After

공통적으로 계속 나타나는 url을 제공하는 부분을 묶는다.

1
String fileUrl = FileInfo.getUrl(fileId);
1
2
3
4
5
6
7
8
public class FileInfo {
    public static String getUrl(fileId) {
        if(fileId.startWith(...)) {
          ...
        }
        ...
    }
}
This post is licensed under CC BY 4.0 by the author.

객체 지향 언어의 특징 - 다형성과 추상화

try-with-resource 사용시 Socket closed 예외 발생