SOLID 원칙
클린 코드로 유명한 로버튼 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리
- SRP: 단일 책임 원칙 (Single Resposibility Principle)
- OCP: 개방-폐쇄 원칙 (Open/Close Principle)
- LSP: 리스코프 치환 원칙 (Loskov Substitution Principle)
- ISP: 인터페이스 분리 원칙 (Interface Segregation Principle)
- DIP: 의존관계 역전 원칙 (Dependency Inversion Principle)
SRP 단일 책임 원칙
- 한 클래스는 하나의 책임만 가져야 한다.
- 중요한 기준은 변경. 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것
- 단일 책임 원칙을 적절하게 조절하여 분리하는 것이 좋은 객체 지향 설계
- 메소드에 또 다른 메소드들을 줄줄이 호출하게 되면, 이는 변경 시 여러 코드에 동시에 영향을 미칠 수 있기 때문에 유지보수에 비효율적이다.
OCP 개발-폐쇄 원칙
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
- 요구사항의 변경이나 추가사항이 발생 하더라도, 기존 구성요소는 수정이 일어나지 말아야 하며, 기존 구성요소를 쉽게 확장해서 재사용 할 수 있어야 한다는 뜻
- OCP를 가능케 하는 중요 메커니즘이 추상화(인터페이스)와 다형성(상속)
- 아래 JDBC 그림을 예로 들면, Applcation에서는 JDBC 인터페이스를 사용하므로 Oracle DB에서 변경이 발생해도 Application에서는 수정할 코드가 없으므로, 변경에는 확장적이지만 수정에는 폐쇄적이다.
LSP 리스코프 치환 원칙
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
- 다형성에서 하위 클래스는 인터페이스의 규약을 지켜야 한다는 것
- 예를 들어, 자동차의 엑셀이라는 인터페이스가 있을 때, 정작 클래스를 뒤로 가도록 구현하면 이는 LSP를 위반한 것임
- 상속 관계에서 부모와 자식간의 관계가 일관성이 있는 관계인지, IS-A 일반화 관계가 성립해야 함
ISP 인터페이스 분리 원칙
- 클라이언트는 자신이 사용하는 인터페이스에만 의존해야 한다.
- 자신이 사용하지 않는 클라이언트를 분리하여 해당 인터페이스가 변경 되어도 다른 인터페이스에 영향을 주지 않도록 해야 함
- 하나의 범용적인 인터페이스보다 클라이언트 기준에 맞게 여러개로 분리된 인터페이스가 더 낫다는 의미
DIP 의존관계 역전 원칙
- 구체화에 의존하지 말고 추상화에 의존하라!
- 구체화된 클래스에 의존하기 보다 추상 클래스나 인터페이스에 의존해야 한다는 것
- 자신보다 변하기 쉬운 것에 의존하지 말아야 한다.
- 고수준 모듈이 저수준 모듈에 의존하지 말아야 한다.
- 저수준(low level) : 파일 입출력, 데이터베이스 통신 같은 기술적 부분을 다루는 모듈(클래스)
- 고수준(high level) : 저수준 클래스를 사용해 비지니스 적인 부분을 다루는 모듈(클래스)
정리
- 객체 지향의 핵심은 다형성인데, 다형성 만으로는 OCP, DIP를 지킬 수 없다.
- Spring에서 OCP 와 DIP를 가능하게 지원하는 것이 DI(Dependecy Injection) 및 DI 컨테이너 임
- SRP 와 ISP 는 객체가 커지고 복잡해지지 않도록 해준다. 객체가 단일 책임을 갖도록 하고 클라이언트마다 특화된 인터페이스를 구현하게 함으로써 한 기능의 변경이 다른 곳까지 미치는 영향을 최소화하고, 이는 기능 추가 및 변경에 용이하도록 만들어 준다.
- LSP 와 DIP 는 OCP 를 서포트한다. OCP 는 자주 변화되는 부분을 추상화하고 다형성을 이용함으로써 기능 확장에는 용이하되 기존 코드의 변화에는 보수적이도록 만들어 준다. 여기서 '변화되는 부분을 추상화'할 수 있도록 도와주는 원칙이 DIP 이고, 다형성 구현을 도와주는 원칙이 LSP이다.
참고 Reference