A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Show 영화 예매 시스템
객체 지향 설계의 초점
영화 예매 객체 구조책에서 아주 자세하게 구조도가 그려져있다.
소스영화 상영 정보변수의 가시성은 private, 메서드의 가시성은 public. (일반적으로 객체의 상태는 숨기고 행동은 공개한다.)
상영 정보 클래스에서 예매 생성(reserve)도 담당하며 이때 전체 예매 금액을 계산한다.
금액 정보int나 long으로 표현 할수 있지만 Money 도메인을 사용하여 명확한 의미전달을 할 수 있다.
예약 정보영화를 예매하기위해 여러 객체의 협력이 발생한다. 상영 정보(reserve) -> 영화 정보에서 예매 금액 계산(calculateMovieFee) -> 예약 정보 생성
영화 정보calculateMoveFee에서는 discountPolicy(할인정책)의 calculateDiscountAmount에 메시지를 보내어 할인 금액을 반환받는다.
할인 정책할인 정책에는 금액 할인과 비율 할인 정책이 존재한다. 두 클래스의 코드가 대부분 비슷하므로 추상클래스(DiscountPolicy)로 부모를 만든뒤 calculateDiscountAmount에서는 여러 할인 정책(DiscountCondition)중 만족하는게 있으면 할인금액을 계산하고
가격 할인 정책할인 금액을 생성자로 받아 해당 할인 금액을 고정적으로 반환한다.
비율 할인 정책비율을 생성자로 받아 상영 정보의 금액에서 비율만큼의 금액을 할인 금액으로 반환한다.
할인조건영화 예매 할인 조건으로 상영 순번 및 기간이 존재한다.
영화 예매 구성 및 실행아래의 예제에서 나홀로집의 경우 1회차의 경우 2000원을 할인해주며 아래처럼 할인 정책과 할인 조건을 자유롭게 설정할 수 있다.
컴파일 타임 의존성과 런타임 의존성소스 코드상에서는 Movie는 DiscountPolicy와 의존성을 가지고 있다.
실제 실행시에는 구체적인 클래스를 생성자로 넘겨 업캐스팅되어 사용되어진다.
이처럼 코드의 의존성과 런타임 의존성은 서로 다를 수 있다. 코드 의존성과 런타임 의존성이 다를경우 실제 이어주는 코드까지 파악해야하므로 이해하기 어려워 지지만 반대로 좀더 유연한 프로그래밍을 가능하게 해준다. (의존성의 양면성) 다형성위의 코드상에서 Movie는 DisCountPolicy에게 메시지를 전송하지만 실제 어떤 메서드가 실행될지는 객체의 클래스가 무엇이냐에 따라 달라진다. 이를 다형성이라 한다. 다시말해 메시지와 메서드를 컴파일 시점이 아닌 실행 시점에 정하며 이를 동적 바인딩 또는 지연 바인딩이라고 한다. 종종 구현은 공유 할 필요가 없으며 순수하게 인터페이스(명세)만 공유하고 싶은때 자바에서는 인터페이스를 사용한다. 구현 상속 vs 인터페이스 상속 추상화추상화 계층만 보면 요구사항을 높은 수준에서 서술할 수 있으며 좀더 유연할 설계가 가능하다. 추상화를 이용해서 상위 정책을 기술하면 기본적인 어플리케이션의 흐름을 기술하는 것을 의미한다. 유연한 설계할인 정책이 없는 경우는 다음과 같이 처리할 수도있다.
위와 같이 해도 정상적으로 동작하나 기존 할인 정책의 경우 DiscountPolicy에 위임 하였으나 할인 정책이 없을 경우만 Movie에서 예외 적으로 처리하고 있음. 조건문(if)를 사용하여 책임의 위치를 변경하는 것은 좋지않다. 예외 케이스를 최소화하고 일관성을 가져야한다. 미할인 정책 추가 및 사용0원 할인 정책을 그대로 수행할 NoneDiscountPolicy클래스를 추가한다.
Movie와 DiscountPolicy를 수정하지않고 NoneDiscountPolicy를 추가하여 어플리케이션을 확장하였다. 추상화가 유연한 설계를 가능케하는 이유는 설계가 구체적인 상황에 결합되는것을 방지하기 때문이다. 유연성이 필요한곳에 추상화를 사용하자! 명확한 의미 전달 - 추상클래스와 인터페이스의 트레이드 오프위의 코드에서 실제 NoneDiscountPolicy는 어떤값을 반환해도 상관이 없다.
동작은 정확히 하나 NoneDiscountPolicy의 의미가 명확하지 않다. DiscountPolicy를 추상클래스에서 인터페이스로 변경한다.
기존의 추상클래스 였던 DiscountPolicy를 DefaultDiscountPolicy로 변경한다.
나머지 원래 할인 정책들은 DiscountPolicy가 아닌 DefaultDiscountPolicy를 구현한다.
NoneDiscountPolicy가 DiscountPolicy 인터페이스를 구현하게 하면 의미가 명확하게 전달된다.
그러나 미할인 정책을 위해 하나의 레이어를 더 두었으므로 그만큼 복잡도는 상승하였다. 상속의 문제점
만약 Movie를 상속한 AmountDiscountMovie와 PercentDiscountMovie가 존재할시 할인 정책을 변경하려면 인스턴스의 정보를 복제하여 인스턴스를 교체해야한다. 인스턴스 변수로 변경시에 아래와같이 간단하게 변경 가능하다. (전체의 행동을 변경(상속)하긴 힘들지만 전체의 틀은 두고 프로세스의 일부분(합성)을 변경할 경우 유연하게 설정 가능하다는 느낌인거 같다.)
합성상속의 경우 컴파일 시점에 강하게 연결되어 있으나 합성의 경우 인터페이스를 통해 약하게 연결된다. 이를 통해 인터페이스에 정의된 메시지를 통서만 재사용이 가능하기때문에 효과적으로 캡슐화 가능하며 의존하는 인스턴스를 쉽게 교체하여 유연하게 사용 가능하다. GIT깃의 소스를 diff해서 보면 더 유용할것이다! https://github.com/oodmumc3/object-book-movie-ticketing oodmumc3/object-book-movie-ticketing 오브젝트 도서 - 영화 예매 시스템 예제. Contribute to oodmumc3/object-book-movie-ticketing development by creating an account on GitHub. github.com 느낀점이번장에서 개인적으로 느낀점은 추상화를 통해 애플리케이션 전체 구조의 밑그림을 그리고 구체적인 기능은 구체적인 클래스들을 만들어 사용/개발하라는 의미를 강하게 받았다. 이번장에서는 추상 클래스와 인터페이스, 다형성, 상속과 합성이 주요 키워드였던거 같다. 추상클래스는 코드를 공유하고 특정 부분만 다를 경우(템플릿 메서드 패턴)에 사용하고 인터페이스는 이와 달리 공유 할 코드가 없을때 사용한다. 상속의 경우는 일반적으로 알고있는 코드 및 메서드 재사용 측면에서 사용하는 것은 지양하고, 다형성을 목표로 인터페이스 공유를 위해 사용하는것을 지향해야한다. 상속의 경우는 부모와 자식의 관계가 컴파일 시점에 정해져 결합도가 높으므로 캡슐화 및 유연성이 떨어진다. 합성을 이용하면 인터페이스를 통해 협력관계가 이어지므로 캡슐화로 결합도가 낮아지며 유연성이 높아진다. 이전에도 썼다시피 자바 서적에서 각자의 의미를 사전적으로 적어놓고 나도 암기적으로 외우고만 있었지 실제로 이런 예제를 통해서 참된 의미를 느낀건 처음이다. 뒤의 내용들도 너무 기대된다. |