Skip to content

[2장_양수진] Pull Request #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 26, 2023
5 changes: 5 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/Customer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package yangsooplus.ch02

data class Customer(
val name: String
)
42 changes: 42 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/Money.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package yangsooplus.ch02

import java.math.BigDecimal

data class Money(val amount: BigDecimal) {

fun plus(other: Money): Money {
return Money(amount.add(other.amount))
}

fun minus(other: Money): Money {
return Money(amount.subtract(other.amount))
}

fun times(percent: Double): Money {
return Money(amount.multiply(BigDecimal.valueOf(percent)))
}

fun times(percent: Int): Money {
return Money(amount.multiply(BigDecimal.valueOf(percent.toLong())))
}

fun isLessThan(other: Money): Boolean {
return amount < other.amount
}

fun isGreaterThanOrEqual(other: Money): Boolean {
return amount >= other.amount
}

companion object {
val ZERO = Money.wons(0)

fun wons(amount: Long): Money {
return Money(BigDecimal.valueOf(amount))
}

fun wons(amount: Double): Money {
return Money(BigDecimal.valueOf(amount))
}
}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/Movie.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package yangsooplus.ch02

import yangsooplus.ch02.policy.DiscountPolicy
import java.time.Duration

data class Movie(
val title: String,
val runningTime: Duration,
val fee: Money,
var discountPolicy: DiscountPolicy
) {
fun calculateMovieFee(screening: Screening): Money{
return fee.minus(discountPolicy.calculateDiscountAmount(screening))
}

fun changeDiscountPolicy(discountPolicy: DiscountPolicy) {
this.discountPolicy = discountPolicy
}
}
49 changes: 49 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## 명심!
1. 어떤 클래스가 필요한지 보다 어떤 **객체**가 필요할지 먼저 고민하자.
2. 객체를 독립적인 존재가 아니라 공동체의 일원으로 보자.

### Domain

- 어떤 문제를 해결하기 위해 사용자가 프로그램을 사용하는 분야

### Message vs Method
- Message
- 메세지를 전송/수신 함으로서 객체는 다른 객체와 상호작용
- Method
- 수신된 메세지를 처리하기 위한 자신만의 방법

### 코드의 의존성 != 실행 시점의 의존성
- 두 의존성이 다를수록 유연하고 확장 가능한 구조. 재사용성⬆ 확장가능성⬆
- but 코드를 이해하기 어려워진다.
- 어떤 인스턴스가 어떤 객체에 의존하고 있는지 알기 위해 의존성을 연결하는 부분을 찾아봐야 함.

### 상속과 인터페이스
- 인터페이스
- 객체가 이해할 수 있는 메세지 목록 정의
- 상속
- 자식 클래스는 부모 클래스의 인터페이스를 물려 받는다
- 코드를 재사용하는 취지보다는 외부 객체가 자식 클래스를 부모 클래스와 동일한 타입으로 간주할 수 있음을 명심
- upcasting
- 자식 클래스가 부모 클래스를 대신하는 것

### 추상화
- 추상화의 계층만 분리하면 요구사항의 정책을 높은 수준에서 서술 가능
- 상위 개념만으로 도메인을 설명할 수 있다.
- 설계가 유연해짐.

### 재사용에는 상속보다는 합성(Composition)
- 합성?
- 다른 객체의 인스턴스를 자신의 인스턴스 변수로 포함해서 재사용하는 방법
- 내가 포함한 객체가 제공하는 메서드는 알고, 내부 구현에 대해선 알지 못한다
- = 인터페이스에 정의된 메세지를 통해서만 코드를 재사용
- 상속의 문제점?
1. 캡슐화를 위반한다. 부모의 구현이 자식에게 노출되고 있다.
- = 자식이 부모에 강하게 결합됨
- = 부모를 변경하면 자식도 변경될 가능성 농후
- ➡ 과도한 상속은 코드 변경을 어렵게 한다.
2. 설계가 유연하지 않음
- 부모와 자식 관계를 컴파일 시점에 결정함
- = 실행 시점에 객체 종류 변경 불가
- 그럼 상속 아예 쓰지마?
- 그건 아니다.
- 다형성을 위해 인터페이스를 재사용하는 경우에는 상속과 합성을 조합해서 사용
8 changes: 8 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/Reservation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package yangsooplus.ch02

data class Reservation(
val customer: Customer,
val screening: Screening,
val fee: Money,
val audienceCount: Int
)
22 changes: 22 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/Screening.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package yangsooplus.ch02

import java.time.LocalDateTime

data class Screening(
val movie: Movie,
val sequence: Int,
val whenScreened: LocalDateTime
) {

fun isSequence(sequence: Int) : Boolean = this.sequence == sequence

fun getMovieFee(): Money = movie.fee

fun reserve(customer: Customer, audienceCount: Int): Reservation {
return Reservation(customer, this, calculateFee(audienceCount), audienceCount)
}

private fun calculateFee(audienceCount: Int): Money {
return movie.calculateMovieFee(this).times(audienceCount)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package yangsooplus.ch02.condition

import yangsooplus.ch02.Screening

interface DiscountCondition {
fun isSatisfiedBy(screening: Screening): Boolean
}
18 changes: 18 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/condition/PeriodCondition.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package yangsooplus.ch02.condition

import yangsooplus.ch02.Screening
import java.time.DayOfWeek
import java.time.LocalTime

class PeriodCondition(
private val dayOfWeek: DayOfWeek,
private val startTime: LocalTime,
private val endTime: LocalTime
): DiscountCondition {

override fun isSatisfiedBy(screening: Screening): Boolean {
return screening.whenScreened.dayOfWeek.equals(dayOfWeek)
&& startTime <= screening.whenScreened.toLocalTime()
&& endTime >= screening.whenScreened.toLocalTime()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package yangsooplus.ch02.condition

import yangsooplus.ch02.Screening

class SequenceCondition(private val sequence: Int): DiscountCondition {
override fun isSatisfiedBy(screening: Screening): Boolean {
return screening.isSequence(sequence)
}
}
15 changes: 15 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/policy/AmountDiscountPolicy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package yangsooplus.ch02.policy

import yangsooplus.ch02.Money
import yangsooplus.ch02.Screening
import yangsooplus.ch02.condition.DiscountCondition

class AmountDiscountPolicy(
private val discountAmount: Money,
private val conditions: List<DiscountCondition>
): DefaultDiscountPolicy(conditions) {

override fun getDiscountAmount(screening: Screening): Money {
return discountAmount
}
}
24 changes: 24 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/policy/DefaultDiscountPolicy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package yangsooplus.ch02.policy

import yangsooplus.ch02.Money
import yangsooplus.ch02.Screening
import yangsooplus.ch02.condition.DiscountCondition

abstract class DefaultDiscountPolicy(
private val conditions: List<DiscountCondition>
) : DiscountPolicy {


override fun calculateDiscountAmount(screening: Screening): Money {
if (conditions.isEmpty()) return Money.ZERO

for (c in conditions) {
if (c.isSatisfiedBy(screening)) return getDiscountAmount(screening)
}

return Money.ZERO
}

protected abstract fun getDiscountAmount(screening: Screening): Money

}
9 changes: 9 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/policy/DiscountPolicy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package yangsooplus.ch02.policy

import yangsooplus.ch02.Money
import yangsooplus.ch02.Screening
import yangsooplus.ch02.condition.DiscountCondition

interface DiscountPolicy{
fun calculateDiscountAmount(screening: Screening): Money
}
10 changes: 10 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/policy/NoneDiscountPolicy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package yangsooplus.ch02.policy

import yangsooplus.ch02.Money
import yangsooplus.ch02.Screening

class NoneDiscountPolicy : DiscountPolicy {
override fun calculateDiscountAmount(screening: Screening): Money {
return Money.ZERO
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/yangsooplus/ch02/policy/PercentDiscountPolicy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package yangsooplus.ch02.policy

import yangsooplus.ch02.Money
import yangsooplus.ch02.Screening
import yangsooplus.ch02.condition.DiscountCondition

class PercentDiscountPolicy(
private val percent: Double,
private val conditions: List<DiscountCondition>
): DefaultDiscountPolicy(conditions) {

override fun getDiscountAmount(screening: Screening): Money {
return screening.getMovieFee().times(percent)
}

}
Loading