-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
441 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,14 @@ | ||
package christmas | ||
|
||
import christmas.controller.ChristmasController | ||
import christmas.service.ChristmasService | ||
import christmas.view.InputView | ||
import christmas.view.OutputView | ||
|
||
fun main() { | ||
TODO("프로그램 구현") | ||
ChristmasController.run( | ||
InputView, | ||
OutputView, | ||
ChristmasService | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package christmas.badge | ||
|
||
import christmas.model.Price | ||
import christmas.validation.ChristmasException | ||
|
||
enum class Badge(val minBenefitAmount: UInt) { | ||
별(5_000u), | ||
트리(10_000u), | ||
산타(20_000u), | ||
; | ||
|
||
companion object { | ||
fun of(benefitAmount: Price) = | ||
when (benefitAmount.value.toUInt()) { | ||
in 0u until 별.minBenefitAmount -> null | ||
in 별.minBenefitAmount until 트리.minBenefitAmount -> 별 | ||
in 트리.minBenefitAmount until 산타.minBenefitAmount -> 트리 | ||
in 산타.minBenefitAmount until UInt.MAX_VALUE -> 산타 | ||
else -> throw ChristmasException("말도 안되는 혜택 금액입니다. 혜택 금액: $benefitAmount") | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
kotlin-christmas/src/main/kotlin/christmas/controller/ChristmasController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package christmas.controller | ||
|
||
import christmas.service.ChristmasService | ||
import christmas.view.InputView | ||
import christmas.view.OutputView | ||
|
||
object ChristmasController { | ||
fun run( | ||
inputView: InputView, | ||
outputView: OutputView, | ||
christmasService: ChristmasService, | ||
) { | ||
outputView.printWelcomeMessage() | ||
val userOrderInfo = inputView.getUserOrderInfo() | ||
val benefitInfo = christmasService.getBenefitInfo(userOrderInfo) | ||
outputView.printUserEventBenefit(userOrderInfo, benefitInfo) | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
kotlin-christmas/src/main/kotlin/christmas/event/EventPolicy.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package christmas.event | ||
|
||
import christmas.menu.Menu | ||
import christmas.menu.MenuType | ||
import christmas.menu.MenuWithCount | ||
import christmas.model.Price | ||
import christmas.model.UserOrderInfo | ||
import java.time.DayOfWeek | ||
import java.time.LocalDate | ||
import java.time.Month | ||
|
||
private const val MIN_EVENT_PRICE = 10_000 | ||
|
||
enum class EventPolicy { | ||
GiveawayEventPolicy { | ||
override fun isOwnSupported(userOrderInfo: UserOrderInfo) = userOrderInfo.totalPrice >= 120_000 | ||
|
||
override fun getBenefit(userOrderInfo: UserOrderInfo): EventType = | ||
EventType.Giveaway(MenuWithCount(Menu.샴페인, 1), this.getPolicyName()) | ||
|
||
override fun getPolicyName() = "증정 이벤트" | ||
}, | ||
|
||
ChristmasDiscountPolicy { | ||
override fun isOwnSupported(userOrderInfo: UserOrderInfo) = | ||
userOrderInfo.estimatedVisitDate.isBefore(LocalDate.of(2023, 12, 26)) | ||
|
||
override fun getBenefit(userOrderInfo: UserOrderInfo) = | ||
EventType.Discount( | ||
Price(1000 + 100 * (userOrderInfo.estimatedVisitDate.dayOfMonth - 1)), | ||
this.getPolicyName() | ||
) | ||
|
||
override fun getPolicyName() = "크리스마스 디데이 할인" | ||
}, | ||
|
||
WeekdayDiscountPolicy { | ||
private val discountPricePerMenu = 2023 | ||
private val availableDiscountDayOfWeek = listOf( | ||
DayOfWeek.MONDAY, | ||
DayOfWeek.TUESDAY, | ||
DayOfWeek.WEDNESDAY, | ||
DayOfWeek.THURSDAY, | ||
DayOfWeek.FRIDAY | ||
) | ||
|
||
override fun isOwnSupported(userOrderInfo: UserOrderInfo) = | ||
availableDiscountDayOfWeek.contains(userOrderInfo.estimatedVisitDate.dayOfWeek) | ||
|
||
override fun getBenefit(userOrderInfo: UserOrderInfo) = | ||
EventType.Discount( | ||
Price(userOrderInfo.getSumPriceOfMenu(MenuType.Dessert) * discountPricePerMenu), | ||
this.getPolicyName() | ||
) | ||
|
||
override fun getPolicyName() = "평일 할인" | ||
}, | ||
|
||
WeekendDiscountPolicy { | ||
private val discountPricePerMenu = 2023 | ||
private val availableDiscountDayOfWeek = listOf(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY) | ||
|
||
override fun isOwnSupported(userOrderInfo: UserOrderInfo) = | ||
availableDiscountDayOfWeek.contains(userOrderInfo.estimatedVisitDate.dayOfWeek) | ||
|
||
override fun getBenefit(userOrderInfo: UserOrderInfo) = | ||
EventType.Discount( | ||
Price(userOrderInfo.getSumPriceOfMenu(MenuType.Main) * discountPricePerMenu), | ||
this.getPolicyName() | ||
) | ||
|
||
override fun getPolicyName() = "주말 할인" | ||
}, | ||
|
||
SpecialDiscountPolicy { | ||
private val discountPrice = 1000 | ||
private val availableDiscountDay = listOf( | ||
LocalDate.of(2023, 12, 3), | ||
LocalDate.of(2023, 12, 10), | ||
LocalDate.of(2023, 12, 17), | ||
LocalDate.of(2023, 12, 24), | ||
LocalDate.of(2023, 12, 25), | ||
LocalDate.of(2023, 12, 31), | ||
) | ||
|
||
override fun isOwnSupported(userOrderInfo: UserOrderInfo) = | ||
availableDiscountDay.contains(userOrderInfo.estimatedVisitDate) | ||
|
||
override fun getBenefit(userOrderInfo: UserOrderInfo) = | ||
EventType.Discount(Price(discountPrice), this.getPolicyName()) | ||
|
||
override fun getPolicyName() = "특별 할인" | ||
}, | ||
; | ||
|
||
fun isSupported(userOrderInfo: UserOrderInfo) = | ||
userOrderInfo.totalPrice >= MIN_EVENT_PRICE && | ||
isInEventDate(userOrderInfo) && | ||
isOwnSupported(userOrderInfo) | ||
|
||
private fun isInEventDate(userOrderInfo: UserOrderInfo) = | ||
userOrderInfo.estimatedVisitDate.year == 2023 && userOrderInfo.estimatedVisitDate.month == Month.DECEMBER | ||
|
||
protected abstract fun isOwnSupported(userOrderInfo: UserOrderInfo): Boolean | ||
|
||
abstract fun getBenefit(userOrderInfo: UserOrderInfo): EventType | ||
|
||
protected abstract fun getPolicyName(): String | ||
} |
16 changes: 16 additions & 0 deletions
16
kotlin-christmas/src/main/kotlin/christmas/event/EventType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package christmas.event | ||
|
||
import christmas.menu.MenuWithCount | ||
import christmas.model.Price | ||
|
||
sealed class EventType( | ||
private val benefitAmount: Price, | ||
private val eventPolicyName: String | ||
) { | ||
class Discount(val price: Price, eventPolicyName: String) : EventType(price, eventPolicyName) | ||
|
||
class Giveaway(val menuWithCount: MenuWithCount, eventPolicyName: String) : | ||
EventType(menuWithCount.benefitAmount, eventPolicyName) | ||
|
||
override fun toString() = "${eventPolicyName}: ${benefitAmount.toMinusString()}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package christmas.menu | ||
|
||
import christmas.model.Price | ||
|
||
enum class Menu(val price: Price, val menuType: MenuType) { | ||
양송이스프(Price(6_000), MenuType.Appetizer), | ||
타파스(Price(5_500), MenuType.Appetizer), | ||
시저샐러드(Price(8_000), MenuType.Appetizer), | ||
티본스테이크(Price(55_000), MenuType.Main), | ||
바비큐립(Price(54_000), MenuType.Main), | ||
해산물파스타(Price(35_000), MenuType.Main), | ||
크리스마스파스타(Price(25_000), MenuType.Main), | ||
초코케이크(Price(15_000), MenuType.Dessert), | ||
아이스크림(Price(5_000), MenuType.Dessert), | ||
제로콜라(Price(3_000), MenuType.Drink), | ||
레드와인(Price(60_000), MenuType.Drink), | ||
샴페인(Price(25_000), MenuType.Drink), | ||
; | ||
|
||
} | ||
|
||
enum class MenuType { | ||
Appetizer, | ||
Main, | ||
Dessert, | ||
Drink, | ||
; | ||
} | ||
|
||
data class MenuWithCount(val menu: Menu, val count: Int) { | ||
val benefitAmount = menu.price * count | ||
|
||
override fun toString() = "${this.menu.name} ${this.count}개" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package christmas.model | ||
|
||
import christmas.validation.requireChristmas | ||
import java.text.DecimalFormat | ||
|
||
@JvmInline | ||
value class Price(val value: Int) { | ||
init { | ||
requireChristmas(value >= 0) | ||
} | ||
|
||
operator fun times(other: Int) = Price(this.value * other) | ||
|
||
operator fun plus(other: Price) = Price(this.value + other.value) | ||
|
||
operator fun minus(other: Price) = Price(this.value - other.value) | ||
|
||
operator fun compareTo(other: Price) = this.value.compareTo(other.value) | ||
|
||
operator fun compareTo(other: Int) = this.value.compareTo(other) | ||
|
||
fun toMinusString() = "${DecimalFormat("#,###").format(-value)}원" | ||
|
||
override fun toString() = "${DecimalFormat("#,###").format(value)}원" | ||
} | ||
|
||
fun Int.toPrice() = Price(this) |
25 changes: 25 additions & 0 deletions
25
kotlin-christmas/src/main/kotlin/christmas/model/UserBenefitInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package christmas.model | ||
|
||
import christmas.badge.Badge | ||
import christmas.event.EventType | ||
|
||
class UserBenefitInfo( | ||
val benefitList: List<EventType>, | ||
) { | ||
val giveaway: EventType.Giveaway? = benefitList | ||
.filterIsInstance<EventType.Giveaway>().firstOrNull() | ||
|
||
val totalBenefitAmount: Price = benefitList.sumOf { | ||
when (it) { | ||
is EventType.Giveaway -> it.menuWithCount.menu.price.value * it.menuWithCount.count | ||
is EventType.Discount -> it.price.value | ||
} | ||
}.toPrice() | ||
|
||
val totalDiscountAmount: Price = benefitList | ||
.filterIsInstance<EventType.Discount>() | ||
.sumOf { it.price.value } | ||
.toPrice() | ||
|
||
val eventBadge = Badge.of(totalBenefitAmount) | ||
} |
38 changes: 38 additions & 0 deletions
38
kotlin-christmas/src/main/kotlin/christmas/model/UserOrderInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package christmas.model | ||
|
||
import christmas.menu.MenuType | ||
import christmas.menu.MenuWithCount | ||
import christmas.validation.requireChristmas | ||
import java.time.LocalDate | ||
|
||
private const val MAX_AVAILABLE_MENU_COUNT = 20 | ||
|
||
class UserOrderInfo( | ||
val userOrderMenu: UserOrderMenu, | ||
estimatedVisitDay: VisitDay, | ||
) { | ||
val estimatedVisitDate: LocalDate = LocalDate.of(2023, 12, estimatedVisitDay.day) | ||
val totalPrice: Price = userOrderMenu.getTotalPrice() | ||
|
||
fun getSumPriceOfMenu(menuType: MenuType) = | ||
this.userOrderMenu.menus.sumOf { if (it.menu.menuType == menuType) it.count else 0 } | ||
|
||
@JvmInline | ||
value class VisitDay(val day: Int) { | ||
init { | ||
requireChristmas(day in 1..31) { "유효하지 않은 날짜입니다. 다시 입력해 주세요." } | ||
} | ||
} | ||
|
||
@JvmInline | ||
value class UserOrderMenu(val menus: List<MenuWithCount>) { | ||
init { | ||
requireChristmas(menus.sumOf { it.count } <= MAX_AVAILABLE_MENU_COUNT) { "totalMenuCount는 ${MAX_AVAILABLE_MENU_COUNT}개를 넘을 수 없습니다." } | ||
requireChristmas((menus.all { it.menu.menuType == MenuType.Drink }).not()) { "음료만 주문할 수 없습니다. 주문 메뉴: $menus" } | ||
} | ||
|
||
fun getTotalPrice() = this.menus.sumOf { it.menu.price.value * it.count }.toPrice() | ||
|
||
override fun toString() = menus.joinToString("\n") | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
kotlin-christmas/src/main/kotlin/christmas/service/ChristmasService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package christmas.service | ||
|
||
import christmas.event.EventPolicy | ||
import christmas.event.EventType | ||
import christmas.model.UserBenefitInfo | ||
import christmas.model.UserOrderInfo | ||
|
||
object ChristmasService { | ||
|
||
private val eventPolicyList = EventPolicy.entries | ||
|
||
fun getBenefitInfo(userOrderInfo: UserOrderInfo) = UserBenefitInfo(getBenefitList(userOrderInfo)) | ||
|
||
private fun getBenefitList(userOrderInfo: UserOrderInfo) = | ||
mutableListOf<EventType>().apply { | ||
for (eventPolicy in eventPolicyList) { | ||
if (eventPolicy.isSupported(userOrderInfo)) { | ||
this.add(eventPolicy.getBenefit(userOrderInfo)) | ||
} | ||
} | ||
}.toList() | ||
} |
17 changes: 17 additions & 0 deletions
17
kotlin-christmas/src/main/kotlin/christmas/validation/LottoValidation.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package christmas.validation | ||
|
||
const val ERROR_PREFIX = "[ERROR] " | ||
|
||
fun requireChristmas(value: Boolean) { | ||
requireChristmas(value) { "Failed requirement." } | ||
} | ||
|
||
inline fun requireChristmas(value: Boolean, lazyMessage: () -> Any) { | ||
if (!value) { | ||
throw ChristmasException(lazyMessage().toString()) | ||
} | ||
} | ||
|
||
class ChristmasException(message: String) : IllegalArgumentException() { | ||
override val message = ERROR_PREFIX + message | ||
} |
Oops, something went wrong.