-
(4) 좋은 객체지향 설계 5원칙 (SOLID)자바 Study/Spring - 핵심원리 2021. 7. 20. 06:30
> 내 이전글 참조
https://korshika.tistory.com/94?category=962145
https://korshika.tistory.com/37?category=962145
1. SOLID 의 종류
※ 객체지향은 다형성 + SOLID가 가장 중요한 특징
> JAVA기준
(1) interface + (Overriding/inheritance) 로 다형성 확보
(2) SOLID란 (1)번을 지키기위한 OOP-Java class 개발 원칙
1-1) SOLID란?
- SRP : 단일 책임 원칙( Single Responsibility Prinicple )
- OCP : 개방-폐쇄 원칙( Open-Closed Principle )
- LSP : 리스코프 치환 원칙( Liskov substitution Principle )
- ISP : 인터페이스 분리 원칙( Interface segregation Principle )
- DIP : 의존관계 역전 원칙( Dependency Inversion Principle )
2. SRP 단일 책임 원칙
2-1) 정의
- 한 클래스는 하나의 책임만 가져야 한다
- 하나의 책임이라는 정의는 모호성이 있음
- 클 수도 있고, 작은 클래스일 수도 있음
- 문맥과 상황에 따라 다름 - 중요한 기준은 변경, 변경이 있을 때
한 클래스안에서만 영향이 크면 클수록 단일 책임 원칙이 지켜지는 것
-> ex) UI 변경, 객체의 생성과 사용을 분리
(그렇다고 너무 작은 책임은 narrow 해지고 단일책임이 깨질 수 있어(?) 마찬가지로 불편하므로 적절한 범위가 필요)
3. OCP 개방-폐쇄 원칙
3-1) 정의
- 확장에는 열려 있으나, 변경에는 닫혀있어야 함
- 가능한가? → 확장을 하려면 기존 코드를 변경? → 무슨의미인지...?
- 객체지향에서 확장 open / 변경 closed하며 코드 변경은 "다형성" 활용
- 확장을 할 때 "역할"이 추가되는 것이므로, interface의 기능을 "추가" 하여 새로운 추가 역할 생성 후
"다형성"을 통해 기능을 구현(or 오버라이딩 통해 역할 수정-역할추가 없을시)
※ 인터페이스를 추가 혹은 오버라딩하여 사용하는 것은 결국 기존 역할이 잘 define 되어있기에 가능한 것
> 기존 예시
3-2) 문제점
기존 예시 상황은 분명 코드의 수정이 있었음
클래스를 직접 선택하는 빌더 패턴의 MemberService 클래스의 코드를 수정해주어야 함
(Interface인 MemberRepository는 변경이 없고, 오버라이딩을 통해 확장을 하여, 여기까지는 OCP가 지켜져도)
- 문제 원인 : MemberService 클라이언트가 구현 클래스를 직접 선택
- 구현 객체를(MebmerRepository m) 변경하려면 클라이언트 코드를 변경해야 한다
= 서버라는 세상에 대해 클라이언트의 객체의 구현부분이 일일이 맞춰주어야 함(역할-interface는 안변했어도)
= 다형성을 사용했지만 OCP 원칙을 지킬 수 없음
3-3) 해결
객체를 생성하고, 연관관계를 맺어주는 별도의 조립 / 설정자가 필요
= 이것을 Spring Container라는 것이 해줌 + DI / IOC 컨테이너
4. LSP 리스코프 치환 원칙
4-1) 정의
- 프로그램 객체는 프로그램 정확성을 깨뜨리지 않으면서 하위 타입(상속-자식)의 인스턴스로 바꿀 수 있어야 함
※ 예시
- 자동차 인터페이스가 있음
- 구현체로 구현을 하는데, 엑셀을 앞으로 가게 구현을 해야하며
- 컴파일의 단계가 아닌, 기능을 의미하는 것 - 하위 클래스가 상위 인터페이스의 기능을 잘 따라서
구현체가 swap되어도 그 기능을 만족할 수 있는 것을 의미 - 다형성에서 하위 클래스는 인터페이스 규약을 따르고 있어야 다형성을 지원할 수 있는데
이를 위해 이 원칙이 필요 - 단순히 컴파일이 성공하는 의미가 아님
- ex) 자동차의 인터페이스인 엑셀은 앞으로 가는 기능, 후진을 한다면 LSP 위반 - 느리더라도 앞으로 전진해야 함
5. ISP 인터페이스 분리 원칙
5-1) 정의
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 보다 낫다
※ 예시
자동차 - 운전자 model 에서, (Server-Client)
1) 자동차 인터페이스 → 운전 인터페이스 ,정비 인터페이스로 분리
2) 사용자 클라이언트 → 운전자 클라이언트, 정비사 클라이언트로 분리
=> 분리를 통해 정비 인터페이스가 변해도, 운전자 클라이언트에 영향을 주지 않음
- 인터페이스가 명확해지고, 대체 가능성이 높아짐
6. DIP 의존관계 역전 원칙
6-1) 정의
- 프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안됨
= 자식 클래스 / 구현체의 구현으로 클래스를 의존시키면 안됨
- 의존성 주입은 이 원칙을 따르는 방법의 하나
- [앞선 예시에서]
클라이언트가 구현 클래스를 바라보지 말고, 인터페이스를 바라봐야 함
== MemberService가 MemberRepository 인터페이스만 바라보고, Memory / JDBC를 바라보면 안됨 - 구현 클래스에 의존하면 안되고(특정 기능을 구현체에만 추가하는 등)
인터페이스에 추가하고 의존하라는 뜻 - [앞의 강에서] "역할"에 의존하라는 것이고, "구현"에 의존하지 말라는 것
의존이라는 것은 "내" 관점에서 해당 구현 코드에서 알고 있으면 의존하는 것
- 객체 세상도 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있음
- 구현체에 의존하게 되면, 변경이 아주 어려워짐
6-2) 예시
-> MemberRepository가 변경되려면 직접 코드 변경을 해야 한다
7. 정리
- 객체 지향의 핵심은 "다형성"
- 다형성만으로는 쉽게 부품을 갈아 끼우듯이 개발할 수 없음
-> 구현 객체를 변경할 때 클라이언트 코드가 함께 변경되어야 하므로 - 따라서 OCP, DIP가 지켜지지 않아 클라이언트 범위에서 객체지향의 장점이 없어진다
- 해결을 위해서는 뭔가 더 필요함
참조
목차 : 객체지향 설계와 스프링
- 좋은 객체지향 설계의 5가지 원칙 (SOLID)반응형'자바 Study > Spring - 핵심원리' 카테고리의 다른 글
(5) 객체 지향 설계와 스프링 (0) 2021.07.22 (3) 좋은 객체지향 프로그래밍 (0) 2021.07.13 (2) 강의 입문 (0) 2021.07.10 (1) 강의 입문 (0) 2021.07.10