객체지향 프로그래밍이란
일반적으로 나열하는 형식의 프로그래밍에서 벗어나
객체를 중심으로 프로그래밍하는 것을 의미한다.
좋은객체지향 프로그래밍이란
역할과 구현을 잘 구분한 프로그래밍이다.
즉, 인터페이스와 구현클래스로 나누어 프로그래밍 하는 것을 의미한다.
인터페이스와 구현클래스를 나누면 좋은 이유는
변화에 대비하는 프로그래밍이기 때문이다.
예를들어, 영화관에서 A할인정책을 시행하고 있다고 하자.
이때, B할인정책으로 바꿀려고 한다.
만약, 할인정책을 인터페이스로 두지 않고, A할인정책 클래스, B할인정책 클래스가 구현되어 있다면,
각 할인정책마다 공통적인 코드가 중복되어서 코드가 간결하지 않을 수 있고,
여러 개발자가 함께 개발하는 환경에서, 해당 할인 정책이 어떤 메소드를 가지고 있는지
알기 위해서는 구현 클래스를 직접 까봐야 한다. OCP, DIP가 위반된다.
하지만 인터페이스과 구현클래스를 나누면, 개발자는 인터페이스에 선언된 메소드만으로도
해당 클래스가 어떤 메소드를 가지고 있고, 해당 메소드가 어떤 일을 수행하는지 대략적으로 알 수 있다.
또한, A, B 할인정책 말고도 C할인정책이라는 새로운 정책을 시행할때에도, 물론 C할인정책은 자바 코드로
구현해야 하지만 구현만 한다면, 이후의 할인정책을 C로 선택하는 것은 OCP, DIP를 지킬수 있다.
객체지향 프로그래밍의 핵심인 5가지 원칙(SOLID)에 대해서 알아보자면,
SRP | 단일 책임 원칙 (Single responsibility principle) 한 클래스는 하나의 책임만 가져야 한다. |
OCP | 개방-폐쇄 원칙 (Open/closed principle) “소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.” |
LSP | 리스코프 치환 원칙 (Liskov substitution principle) “프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.” 계약에 의한 설계를 참고하라. |
ISP | 인터페이스 분리 원칙 (Interface segregation principle) “특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.” |
DIP | 의존관계 역전 원칙 (Dependency inversion principle) 프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.”[4] 의존성 주입은 이 원칙을 따르는 방법 중 하나다. |
DIP는 추상화에 의존하고, 구체화에 의존하지 않는다는 원칙이다.
즉 인터페이스에 의존하고, 구현클래스에 의존하지 않는다는 뜻이다.
영화관이 하나의 할인정책만을 가진다고 생각해보자.
영화관은 할인정책이라는 하나의 인터페이스만을 알고 있어야한다.
하지만, 인터페이스가 없고, 구현클래스만 있다면,
영화관은 처음에 A할인정책을 가지고 있을것이고, 이는 DIP위반이 된다.
왜냐하면 할인정책이라는 인터페이스에만 의존하고, 해당 인터페이스를 구현한 클래스가 A할인정책이어야 하기 때문이다.
그렇다면 OCP위반은 언제 일어날까?
OCP위반은 A정책을 B정책으로 바꿀때 일어난다.
만약 인터페이스가 구현되어 있지 않다면, 영화관은 A정책을 버리고 B정책을 선택할때 B정책 구현 클래스에 의존할 것이다.
인터페이스로 역할과 구현을 나눈다면 영화관은 A정책을 시행하던 B정책을 시행하던, 할인정책 인터페이스만을
가지고 있으면, 해당 인터페이스를 구현한 클래스를 지정하거나, 의존관계 주입을 통해서
어떤 할인정책을 쓸 것인지 쉽게 변경할 수 있다. 따라서, 영화관 객체의 코드는 바꾸지 않을 수 있기 때문에
OCP를 지킬 수 있다.