Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.johngrib.objects._02_movie;

/**
* 금액 할인 정책.
* <p>
* 조건을 만족할 경우 일정 금액을 할인해주는 정책.
*/
public class AmountDiscountPolicy extends DefaultDiscountPolicy {
/** 할인 요금. */
private Money discountAmount;

public AmountDiscountPolicy(Money discountAmount, DiscountCondition... conditions) {
super(conditions);
this.discountAmount = discountAmount;
}

@Override
protected Money getDiscountAmount(Screening screening) {
return discountAmount;
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/Customer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.johngrib.objects._02_movie;

public class Customer {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.johngrib.objects._02_movie;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/** 기본 할인 정책. */
public abstract class DefaultDiscountPolicy implements DiscountPolicy {
/** 하나의 할인 정책은 여러 개의 할인 조건을 포함할 수 있다. */
private List<DiscountCondition> conditions = new ArrayList<>();

public DefaultDiscountPolicy(DiscountCondition... conditions) {
this.conditions = Arrays.asList(conditions);
}

/**
* 할인 금액을 계산한다.
* <p>
* Template Method.
*
* @param screening
* @return
*/
@Override
public Money calculateDiscountAmount(Screening screening) {
for (DiscountCondition each : conditions) {
if (each.isSatisfiedBy(screening)) {
return getDiscountAmount(screening);
}
}
return Money.ZERO;
}

abstract protected Money getDiscountAmount(Screening screening);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.johngrib.objects._02_movie;

/** 할인 조건. */
public interface DiscountCondition {
/**
* 전달된 상영 정보가 할인 조건을 만족시키면 true 를 리턴한다.
*
* @param screening 상영 정보
* @return 할인 조건을 만족했다면 true
*/
boolean isSatisfiedBy(Screening screening);
}
12 changes: 12 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/DiscountPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.johngrib.objects._02_movie;

/** 할인 정책. */
public interface DiscountPolicy {
/**
* 할인 금액을 계산한다.
*
* @param screening 상영 정보
* @return 할인 금액
*/
Money calculateDiscountAmount(Screening screening);
}
47 changes: 47 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/Money.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.johngrib.objects._02_movie;

import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.math.BigDecimal;

/** 금액. */
@EqualsAndHashCode
@ToString
public class Money {
public static final Money ZERO = Money.wons(0);

private final BigDecimal amount;

public static Money wons(long amount) {
return new Money(BigDecimal.valueOf(amount));
}

public static Money wons(double amount) {
return new Money(BigDecimal.valueOf(amount));
}

Money(BigDecimal amount) {
this.amount = amount;
}

public Money plus(Money amount) {
return new Money(this.amount.add(amount.amount));
}

public Money minus(Money amount) {
return new Money(this.amount.subtract(amount.amount));
}

public Money times(double percent) {
return new Money(this.amount.multiply(BigDecimal.valueOf(percent)));
}

public boolean isLessThan(Money other) {
return amount.compareTo(other.amount) < 0;
}

public boolean isGreaterThanOrEqual(Money other) {
return amount.compareTo(other.amount) >= 0;
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/Movie.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.johngrib.objects._02_movie;

import lombok.Getter;

import java.time.Duration;

/** 영화. */
public class Movie {
private String title;
private Duration runningTime;
/** 기본 요금. */
@Getter
private Money fee;
/** 할인 정책. */
private DiscountPolicy discountPolicy;

public Movie(String title, Duration runningTime, Money fee, DiscountPolicy discountPolicy) {
this.title = title;
this.runningTime = runningTime;
this.fee = fee;
this.discountPolicy = discountPolicy;
}

/**
* 할인된 금액을 계산해 리턴한다.
*
* @param screening 상영 정보
* @return 할인된 금액
*/
public Money calculateMovieFee(Screening screening) {
if (discountPolicy == null) {
return fee;
}
return fee.minus(discountPolicy.calculateDiscountAmount(screening));
}

/**
* 실행 시점에 할인 정책을 변경한다.
*
* @param discountPolicy 변경할 할인 정책.
*/
public void changeDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.johngrib.objects._02_movie;

/**
* 할인하지 않는 할인 정책.
*/
public class NoneDiscountPolicy implements DiscountPolicy {
@Override
public Money calculateDiscountAmount(Screening screening) {
return Money.ZERO;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.johngrib.objects._02_movie;

/** 일정 비율 할인 정책. */
public class PercentDiscountPolicy extends DefaultDiscountPolicy {
/** 할인 비율. */
private double percent;

public PercentDiscountPolicy(double percent, DiscountCondition... conditions) {
super(conditions);
this.percent = percent;
}

@Override
protected Money getDiscountAmount(Screening screening) {
return screening.getMovieFee().times(percent);
}
}
31 changes: 31 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/PeriodCondition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.johngrib.objects._02_movie;

import java.time.DayOfWeek;
import java.time.LocalTime;

/** 상영 기간 기준 할인 조건. */
public class PeriodCondition implements DiscountCondition {
/** 요일 */
private DayOfWeek dayOfWeek;
private LocalTime startTime;
private LocalTime endTime;

public PeriodCondition(DayOfWeek dayOfWeek, LocalTime startTime, LocalTime endTime) {
this.dayOfWeek = dayOfWeek;
this.startTime = startTime;
this.endTime = endTime;
}

/**
* 상영 시작 시간이 기간 안에 포함된다면 true 를 리턴한다.
*
* @param screening 상영 정보
* @return 할인 기준을 만족하면 true.
*/
@Override
public boolean isSatisfiedBy(Screening screening) {
return screening.getStartTime().getDayOfWeek().equals(dayOfWeek)
&& startTime.compareTo(screening.getStartTime().toLocalTime()) <= 0
&& endTime.compareTo(screening.getStartTime().toLocalTime()) >= 0;
}
}
3 changes: 3 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 02. 객체지향 프로그래밍

영화 예매 시스템
20 changes: 20 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/Reservation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.johngrib.objects._02_movie;

/** 예매 정보. */
public class Reservation {
/** 고객. */
private Customer customer;
/** 상영 정보. */
private Screening screening;
/** 예매 요금. */
private Money fee;
/** 인원 수. */
private int audienceCount;

public Reservation(Customer customer, Screening screening, Money fee, int audienceCount) {
this.customer = customer;
this.screening = screening;
this.fee = fee;
this.audienceCount = audienceCount;
}
}
56 changes: 56 additions & 0 deletions src/main/java/com/johngrib/objects/_02_movie/Screening.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.johngrib.objects._02_movie;

import java.time.LocalDateTime;

/** 상영. 상영은 사용자들이 예매하는 대상이다. */
public class Screening {
/** 상영할 영화. */
private Movie movie;
/** 상영 순번. */
private int sequence;
/** 상영 시작 시간. */
private LocalDateTime whenScreened;

public Screening(Movie movie, int sequence, LocalDateTime whenScreened) {
this.movie = movie;
this.sequence = sequence;
this.whenScreened = whenScreened;
}

/** 상영 시작 시간을 리턴한다. */
public LocalDateTime getStartTime() {
return whenScreened;
}

/** 순번이 일치하면 true 를 리턴한다. */
public boolean isSequence(int sequence) {
return this.sequence == sequence;
}

/** 기본 요금을 리턴한다. */
public Money getMovieFee() {
return movie.getFee();
}

/**
* 영화를 예매하고, 예매 정보를 리턴한다.
*
* @param customer 예매자
* @param audienceCount 예매 인원 수
* @return 예매 정보
*/
public Reservation reserve(Customer customer, int audienceCount) {
return new Reservation(customer, this, calculateFee(audienceCount), audienceCount);
}

/**
* 전체 예매 요금을 계산해 리턴한다.
*
* @param audienceCount 예매 인원 수
* @return 예매 요금
*/
private Money calculateFee(int audienceCount) {
return movie.calculateMovieFee(this)
.times(audienceCount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.johngrib.objects._02_movie;

/** 순번 기준 할인 조건. */
public class SequenceCondition implements DiscountCondition {
/** 순번. */
private int sequence;

public SequenceCondition(int sequence) {
this.sequence = sequence;
}

@Override
public boolean isSatisfiedBy(Screening screening) {
return screening.isSequence(sequence);
}
}
Loading