객체지향 설계
남에게 설명한다는 생각으로,,,프로젝트 시 팀원에게 설명한다는 생각으로,,,
객체지향 설계 방법
- 역할과 구현 이 두가지를 분리해야함.
단순한 예로 항상 연극을 떠올리자, 로미오와 줄리엣 연극을 한다했을때, 역할에는 로미오, 줄리엣 두가지가 있고 구현(배우)으로는 장동건, 고소영 이 있다고 생각하자.'
역할 => 로미오
구현 => 원빈
역할 => 객체
구현 => 인스턴스
로미오 역할 => 클라이언트
줄리엣 역할 => 서버
-
이때, 줄리엣 배우가 고소영에서 신민아로 바뀜 => 서버에 대한 구현체가 변경됨
고소영에서 신민아로 바뀐다고 로미오의 역할이나, 장동건이 영향을 받는가?
좋은 객체지향 설계라면 영향을 전혀 받지않음. -
클라이언트 파트가 요청하는 로직이 있다면 서버파트의 인터페이스를 필두로 각 구현체를 대입하여 클라이언트가 대입된 구현체에서 로직을 꺼내와 실행되도록함.
이해가 안되면 항상 연극을 생각해보자...
다형성?
-
다형성은 좋은 객체지향 설계의 꽃이라고한다. 다형성은 뭘 의미하나?
클라이언트 변경하지않고, 서버의 구현기능을 유연하게 변경할 수 있는것.
-
예시를 들자면 개발도중 DB저장소가 미확정일 경우
회원 저장소라는 인터페이스(역할)을 두고
LocalMemory, DB등 각 상황에 맞는 구현체를 그때 그때 넣을 수 있음.
클라이언트는 인터페이스만 바라보고있으므로 그 구현체가 바뀌든 말든 상관을 안함.
즉, 고소영이 신민아가 되던 로미오 역할에는 변함이없다는것
SOLID 좋은객체지향설계의 5가지 핵심
1. SRP = single responsiblity principle = 각 파일별, 클래스별, 객체의 생성과 사용, UI변경의 기준을 잘 나누어 둔 코드.
- 즉, 변경이있을때 파급효과가 항상 적게 코드를 설계해야함.
2. OCP = open closed principle = 확장에는 열려있으나, 변경에는 닫혀있다.
-
구현체의 추가에는 제한이 없다 => 확장에는 열려있다.
역할과 구현의 분리로 역할 자체의 변경은 불가하다 => 변경에는 닫혀있다.
구현은 바뀔수 있다 (memory -> jdbc -> jpa) -
service는 클라이언트 코드라 약속하자
구현이 바뀔때마다 클라이언트가 구현 클래스(구현체)를 직접 선택하는데
순수 자바코드를 활용했을때는 클라이언트 코드(service)가 필연적으로 변경되어야함
이러면 확장은되지만 변경도되므로 OCP위반
따라서 스프링의 별도의 설정자 (컨테이너)가 필요!!!!
3. LSP = 리스코프 치환원칙 = 일반적인 통용적인 원칙하에 기능을 구현해야함
4. ISP = 인터페이스 분리원칙 = 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다
-
즉 거대한 인터페이스 하나보단 기능별로 쪼개진 인터페이스가 백번 옳다는소리다.
자동차 인터페이스 => 운전 인터페이스, 정비 인터페이스로 분리가능
사용자 클라이언트 => 운전자, 정비사 클라이언트로 각각 분리가능분리하면 정비 인터페이스 자체가 변해도 운전자 클라이언트
에는 영향 x 덩어리가 커지면 구현에 힘들어짐!!!
5. DIP = 의존관계 역전 원칙 = 클라이언트 코드(서비스)가 구현 클래스(구현체)를 바라보지말고 인터페이스만 바라봐야함
-
즉, 역할(인터페이스)에 의존하라는것과 동일한 맥락
시스템도 역할과 구현을 철저하게 분리하여 언제든지 갈아낄수 있게 만들어야함
이때 항상 역할에 의존하게 만들어야함 (DIP) -
클라이언트가 구현클래스 직접 선택 => DIP위반 사례
MemberRepository m = new MemoryMemberRepository(); //구현클레스 직접 지정
정리
-
모든 설계에 역할과 구현을 분리하자
자동차, 공연의 예를 떠올리자
역할을 만들어두고 구현을 유연하게 변경할수 있는게 좋은 객체지향 설계
이상적으로 모든 설계에 인터페이스 부여하자 -
기능을 확장할 가능성이없다면, 구체클래스를 직접 사용하는것도 좋다.
다만, 무분별한 인터페이스 남발은 코드의 과대한 추상화를 불러와 보기힘들어짐(비용증가) -
OCP DIP 고려 안하고 역할과 구현 분리만 이루었을때는
역할이 구체를 선택하거나 하는 상황이 생김
ex) 로미오 배우가 줄리엣 배우를 고르는 상황
하지만 이런경우에는 역할과 구현이 철저하게 분리된 상태라고 보지않음
DIP또한 지키지 못함. -
따라서 공연에서도 공연기획자가 섭외를 담당하듯
역할에 맞는 구현을 연결하는 별도의 책임을 갖는 설정 클래스가 필요함
AppConfig라는 별도의 설정클래스 생성생성자를 만들고 설정클래스상에서 생성자 주입을 통해 구체 연결 가능,
이방법으로 DIP또한 지킬 수 있게된다. (철저하게 인터페이스에만 의존하고,
구체에 관련한 코드는 전혀없어짐) -
객체의 생성과 연결은 AppConfig가 담당한다.
즉 AppConfig가 클라이언트 구현체를 생성함과 동시에 서버 구현체또한 생성하고
이를 주입(인젝션)하므로서 객체의 생성과 연결의 역할은 명확히 분리됨.
Author And Source
이 문제에 관하여(객체지향 설계), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@whiskey21/객체지향-설계저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)