calculateMovieFee 메서드는 discountPolicy 에 calculateDiscountAmount 메시지를 전송해서 할인 요금을 전달받기를 믿는다. 그리고 기본 요금에서 할인 요금만큼 차감한다.
할인 정책에는 (1) 금액 할인 정책 (2) 비율 할인 정책이 있었다. 그런데 위 코드에서는 할인 정책을 표현하지 않고 단지 메세지를 전달한다. 객체지향 패러다임에서 중요한 두 가지 개념이 있다.
하나는 상속(Inheritance), 하나는 다형성(Polymorphism)이다. 그리고 그 기반에는 추상화(Abstraction)라는 원리가 숨겨져있다.
할인 정책은 금액 할인 정책과 비율 할인 정책으로 구분된다. 이 두 객체는 서로 성질이 비슷해서 공통된 클래스가 있으면 좋다. DiscountPolicy 에 공통 속성과 기능을 가지도록 하고, AmountDiscountPolicy 와 PercentDiscountPolicy 가 상속받게한다. 실제 어플리케이션 소비자에서는 DiscountPolicy 인스턴스를 사용하지않기에 추상 클래스로 작성한다.
하나의 DiscountPolicy 는 DiscountCondition 들을 가질 수 있다. calculateDiscountAmount() 는 전체 할인 조건들에 대해서 isSatisfiedBy() 메서드를 호출한다. 할인 조건을 하나라도 만족하면 추상 메서드로 선언한 getDiscountAmount() 를 호출해 할인 요금을 계산한다.
전체적인 할인 여부 및 요금 계산을 관장하지만, 실제 요금 계산은 추상 메서드로 위임한다.
위임한 메서드는 추상 클래스를 상속한 AmountDiscountPolicy.getDiscountAmount, PercentDiscountPolicy.getDiscountAmouunt 가 오버라이딩해 구현한다.
부모 클래스에서 기본적인 알고리즘 흐름을 구현하고, 중간 중간 필요한 처리를 자식 클래스에 위임하는 패턴을 TEMPLATE METHOD 패턴이라고 한다.
오버라이딩은 부모 클래스의 동일한 구조를 가진 메서드 (동일한 이름, 같은 파라미터 목록) 를 재정의하는 것을 말한다. 반면 오버로딩은 메서드의 이름은 같으나 파라미터의 형태, 목록이 다른 경우를 말한다. 오버로딩은 재정의하는 것이 아니라 공존하도록 구현한다. 외부에서는 오버로딩된 함수들을 모두 호출할 수 있다.
하나의 영화에 대해 하나의 할인 정책이 수립된다고 정의했다. 그리고 할인 조건은 여러개를 지정할 수 있었다.