인터페이스 분리 원칙: Interface Segregation Principle
인터페이스 분리 원칙(ISP)이란 객체는 자신이 호출하지 않는 메서드에 의존하지 않아야 한다는 원칙입니다.
ISP의 핵심 키워드는 다음과 같습니다.
- 작은 인터페이스: 작고 구체적인 인터페스로 분리
- 클라이언트: 인터페이스를 사용하는 객체
- 응집력: 인터페이스와 구현 클래스의 높은 응집력
- 의존성 최소화: 불필요한 메서드 의존성 제거
ISP는 인터페이스를 작고 특정한 역할을 수행하도록 분리합니다.
즉, 클라이언트가 자신에게 필요하지 않은 메서드가 종속되지 않도록 하는 것입니다.
ISP를 설명하기 위해 간단한 예제를 보겠습니다.
요구사항
- 스마트폰 최신 기종 S24와 오래 된 S2 기종이 구현해야 한다.
- 통화, 메시지는 스마트폰 일반 기능이다.
- S24는 일반 스마트폰 기능 외 AR 뷰어, 생체 인식 등등 새로운 기능을 포함한다.
- S2는 일반 스마트폰 기능을 가진다.
ISP를 준수하지 않은 코드
SmartPhone이라는 추상 클래스를 상속하여 S24와 S2를 구체 클래스로 구현합니다. 생체 인식을 담당하는 biometrics() 메서드는 기기에 등록된 생체 정보를 활용해야 하므로 추상메서드로 선언하였습니다.
abstract public class SmartPhone {
public void call(String number) {
// 통화
}
public void message(String number, String text) {
// 메시지 전송
}
public void ar() {
// AR 뷰어
}
abstract public void biometrics(); // 추상 클래스를 상속하여 메서드 구현
}
S24는 모든 기능을 사용하기 때문에 SmartPhone 클래스의 모든 메서드를 활용하며, biometrics() 메서드만 따로 구현하면 될 것 같습니다.
public class S20 extends SmartPhone {
@Override
public void biometrics() {
// 생체 인식 구현
}
}
S2는 스마트폰의 일반 기능만 가지고 있으며 그 외 신규 기술은 사용할 수 없습니다.
public class S2 extends SmartPhone {
@Override
public void ar() {
throw new UnsupportedOperationException("This ar is not supported.");
}
@Override
public void biometrics() {
throw new UnsupportedOperationException("This biometrics is not supported.");
}
}
위 코드처럼 지원하지 않는 기능임에도 SmartPhone의 상속으로 인해 해당 기능의 메서드를 강제로 상속받게 됩니다. 이러한 상속의 특징은 부모 클래스의 규모가 클수록, 개발 편의성에 저하로 이뤄지게 됩니다. 필요하지도 않은 수십개의 메서드를 일일히 오버라팅하여 처리해야한다면 번거로울 것입니다. 즉, ISP를 위배하는 코드입니다.
ISP를 준수한 코드
객체지향의 중요한 특성 중 하나는 확장을 통한 구현의 편의성입니다. 이를 위해 상속이 사용되지만, 위 상황에서는 오히려 불편함을 초래하고 있습니다. 위 ISP를 설명할 때, 작은 인터페이스를 사용해야 한다고 했습니다. 이는 객체의 각각의 기능(메서드)을 개별 인터페이스로 분해야 함을 의미합니다.
먼저 스마트폰의 공통적인 기능인 통화와 메시지를 담은 클래스를 구현합니다.
public abstract class SmartPhone {
public void call(String number) {
// 통화 연결
}
public void message(String number, String text) {
// 메시지
}
}
신규 기능이였던 AR, 생체 인식을 삭제하였으며, 각 기능을 인터페이스 단위로 나눕니다.
// AR
public interface ARable {
void ar();
}
// 생체 인식
public interface Biometricsable {
void biometrics();
}
이를 통해 S24와 S2를 구현하면 됩니다.
public class S24 extends SmartPhone implements WirelessChargable, ARable, Biometricsable {
@Override
public void ar() {
// AR 기능 구현
}
@Override
public void biometrics() {
// 생체 인식 구현
}
}
public class S2 extends SmartPhone {
@Override
public void message(String number, String text) {
// S2 메시지 추가 기능
super.message(number, text);
}
}
인터페이스는 다중 상속을 지원하며, 필요한 기능을 인터페이스로 분리하여 해당 기능만 필요한 객체에 상속받을 수 있습니다. 또한 추후에 기능이 추가될 경우 이와 같은 방식으로 인터페이스를 설계하면 필요한 객체에 필요한 기능을 쉽게 추가할 수 있습니다. 이는 ISP를 준수하는 방법입니다.
마치며
인터페이스 분리 원칙은 객체가 반드시 필요한 기능만을 포함하도록 제한하는 원칙입니다. 이는 불필요한 기능의 상속이나 구현을 방지하고 객체가 갖지 않아도 되는 책임을 제거하는 데 중점을 둡니다. 작고 잘 나눠진 인터페이스는 객체의 기능을 명확히 정의하고 필요에 따라 확장할 수 있는 구조를 제공합니다.
LSP를 준수함으로써 객체는 반드시 필요한 기능만을 가지게 되며, 불필요한 책임을 피하고 코드의 유연성과 재사용성을 높일 수 있습니다.이는 좀 더 견고하고 유지보수가 쉬운 소프트웨어를 설계하는 데 도움을 줍니다.
'Spring > Spring Framework' 카테고리의 다른 글
리스코프 치환 원칙(Liskov Subsitution Principle, LSP) (0) | 2024.07.01 |
---|---|
단일 책임의 원칙(Single Responsibility Principle, SRP) (0) | 2024.06.27 |
개방 폐쇄 원칙(Open-Close Principle, OCP) (0) | 2024.06.26 |
의존성 역전 원칙(Dependency Inversion Principle, DIP) (0) | 2024.06.25 |
스프링(Spring)이란? (0) | 2024.02.03 |