반응형
인터페이스 분리 원칙 (Interface segregation principle, ISP)
클라이언트별로 세분화된 인터페이스를 만들어야한다.
인터페이스를 분리한다는 점에서 앞서 1편에서 살펴보았던 단일책임원칙과 동일하다.
그러나 분리하는 관점 자체가 다르다.
인터페이스 분리 원칙이 깨진 상황
public interface Repository {
void createUser();
User findUserById(Long id);
void createArticle();
Article findArticleById(Long id);
}
public class UserRepository implements Repository {
@Override
public void createUser() {
// 의미 있는 어떤 로직
}
@Override
public User findUserById(Long id) {
// 의미 있는 어떤 로직
return null;
}
@Override
public void createArticle() {
// do nothing
}
@Override
public Article findArticleById(Long id) {
// do nothing
return null;
}
}
public class ArticleRepository implements Repository {
@Override
public void createUser() {
// do nothing
}
@Override
public User findUserById(Long id) {
// do nothing
return null;
}
@Override
public void createArticle() {
// 의미 있는 어떤 로직
}
@Override
public Article findArticleById(Long id) {
// 의미 있는 어떤 로직
return null;
}
}
두 개의 Repository 구현체에서 필요없는 메서드들을 Override 해와서 사용하지 않고 있다.
-> 문제가 있어보인다.
이번엔 repository 를 사용하는 Service 를 보자.
public class UserService {
private Repository repository = new UserRepository();
public void createUser() {
repository.createUser();
}
public User findByUser(Long id) {
return repository.findUserById(id);
}
}
public class ArticleService {
private Repository repository = new ArticleRepository();
public void createArticle() {
repository.createArticle();
}
public Article findByArticle(Long id) {
return repository.findArticleById(id);
}
}
언뜻 보기에는 문제가 없어보인다.
하지만 다음 화면을 보면 UserService 가 절대 사용하지 않는 메서드가 불필요하게 노출되는 것을 볼 수 있다.
유지보수하기가 어려울 것이다.
이를 해결하기 위해서
하나의 커다란 인터페이스를 두 개의 인터페이스로 분리하자.
인터페이스 분리 원칙을 지키는 코드
public interface UserRepositoryInterface {
void createUser();
User findUserById(Long id);
}
public interface ArticleRepositoryInterface {
void createArticle();
Article findArticleById(Long id);
}
public class UserRepository implements UserRepositoryInterface {
@Override
public void createUser() {
// 의미 있는 어떤 로직
}
@Override
public User findUserById(Long id) {
// 의미 있는 어떤 로직
return null;
}
}
public class ArticleRepository implements ArticleRepositoryInterface {
@Override
public void createArticle() {
// 의미 있는 어떤 로직
}
@Override
public Article findArticleById(Long id) {
// 의미 있는 어떤 로직
return null;
}
}
인터페이스 분리 원칙을 지키는 코드는
1. 구현 클래스에는 불필요한 메서드를 구현하지 않도록 만들고,
2. 인터페이스를 사용하는 클래스에게는 불필요한 메서드를 노출시키지 않아
유지보수하기 좋은 코드를 만들어준다.
의존관계 역전 원칙 (Dependency inversion principle, DIP)
고수준 컴포넌트는 저수준 컴포넌트에 의존하지 않아야한다.
https://giken.tistory.com/entry/Java-%EC%9D%98%EC%A1%B4-%EC%97%AD%EC%A0%84
[Java] 의존 역전
의존 역전이란 무엇인가? 고수준 컴포넌트가 저수준 컴포넌트에 의존하지 않도록 의존 관계를 역전시키는 것 컴포넌트는 클래스를 의미 인터페이스로 의존 방향이 모이도록 하는 것 고수준 컴
giken.tistory.com
간접적으로 의존 역전 원칙이 깨지는 상황과 그 해결 방법
public interface Repository {
Object findById(Long id);
}
public class Service {
private Repository repository;
public Object findById(Long id) {
Object obj = null;
try {
obj = repository.findById(id);
} catch (RecordNotFoundException recordNotFoundException) {
// 예외에 대한 처리
} catch (TextNotFoundException textNotFoundException) {
// 예외에 대한 처리
} catch (NoSuchElementException noSuchElementException) {
// 예외에 대한 처리
}
return obj;
}
}
Repository 를 상속한 구현체들이
Database Repository, File Repository, ArrayList Repository 가 있다고 해보자.
Service 에서 구현체가 늘어남에 따라서
예외처리하는 코드를 추가해야함을 볼 수 있다.
고수준 컴포넌트인 Service 가 저수준 컴포넌트인 Repository 구현체에 의존하고 있는 것이다.
의존역전원칙을 지키는 코드는
인터페이스를 통해 고수준 컴포넌트가 더 이상 저수준 컴포넌트에 의존하지 않도록 만드는 것이다.
이 때 의존 방향이 역전되기 때문에 의존 역전이라고 한다.
반응형
'Programming Language > Java' 카테고리의 다른 글
[Java] Enum과 Builder 패턴을 예제와 함께 알아보자. (0) | 2023.10.06 |
---|---|
[Java] final 을 사용하는 모든 경우 - 예제와 함께 이해하기 (0) | 2023.09.30 |
[Java] 객체 지향 프로그래밍의 5가지 기본 원칙 SOLID 를 예제와 함께 알아 보자. (1) (0) | 2023.09.27 |
[Java] 의존 관계에 대해 예제와 함께 알아보자. (0) | 2023.09.26 |
[Java] stream API 와 Optional (0) | 2023.09.26 |