역할과 구현을 분리!
- 역할과 구현을 구분하면 세상이 단순해지고, 유연해지며 변경도 편리해진다.
- 장점
- 클라이언트는 대상의 역할(인터페이스)만 알면 됨
- 클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
- 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
- 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다.
자바에서는 어떻게?
- 다형성을 활용함.
- 역할 = 인터페이스
- 구현 = 인터페이스를 구현한 클래스, 구현 객체
- 객체를 설계할 때 역할과 구현을 명확히 분리
- 객체 설계시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체 만들기 ---> 결국 역할이 중요하다.
다형성의 본질 -> 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다. -> 클라이언트에 구속받지 않고 서버의 구현기능을 유연하게 변경 할 수 있다.
좋은 객체 지향 설계의 5가지 원칙 (SOLID)
- SRP : 단일 책임 원칙(Single Responsibility Principle)
- 한 클래스는 하나의 책임만 가져야한다. -> 하지만 하나의 책임이라는 것은 모호하다 그렇다면? 중요한 기준은 변경이다! 변경이 있을 때 파급 효과가 적으면 단일 책임을 잘 따른 것이다.
- OCP : 개방-폐쇄 원칙 (Open Closed Principle)
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다. -> 어떻게? -> 다형성을 활용
- 자동차라는 인터페이스를 사용하여 K9, 포르쉐, 그랜져를 구현되어 있는 상태라고 할 때 새로운 자동차 테슬라가 나왔다고 해보자
OCP를 잘 만족하는 프로그램은 자동차라는 인터페이스에 테슬라를 추가하여 구현하면 된다 --> 테슬라라는 새로운 자동차의 확장에 열려있지만 클라이언트를 따로 변경할 필요없다.
- LSP : 리스코프 치환 원칙 (Liskov Substitution Principle)
- 프로그램의 객체는 프로그램의 정확성을 꺠드리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다. 예를 들어 자동차 인터페이스에 엑셀은 앞으로 가라는 기능을 구현했다고 했을 때, 하위 구현 클래스에서 엑셀이 뒤로 가게 구현을 했다고 하면 이는 LSP를 위배한 사항이 된다.
- ISP : 인터페이스 분리 원칙 (Interface Segregation Principle)
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다 -> 예를 들어 자동차 인터페이스를 운전 인터페이스 , 정비 인터페이스로 분리를 하면, 자동차 클라이언트를 위한 인터페이스, 정비사 클라이언트를 위한 인터페이스로 나누어서 구현이 가능하다 -> 각각 클라이언트는 독립적으로 되고 인터페이스가 명확해지게 된다
- DIP : 의존관계 역전 원칙 (Dependency Inversion Principle)
- 프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다.
- 클라이언트는 인터페이스만 바라봐야 한다. --> 역할에 의존해야한다! 예를 들어 로미오 역할인 연극이 있는데 로미오 배역에 장동건이 있는 상황에서 '나'로 교체가 되어야 하는 상황인데, 내가 로미오 배역을 알고 있는게 아니고 장동건의 출생 이런 정보만 알고 있다고 하면 제대로 된 연극을 하기 어려울 것이다.