Skip to content
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

[개발자 비상근무] 미니언 미션 제출합니다. #19

Open
wants to merge 1 commit into
base: gusah009-main
Choose a base branch
from
Open
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
7 changes: 6 additions & 1 deletion kotlin-oncall/src/main/kotlin/oncall/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package oncall

import oncall.controller.OncallController
import oncall.service.OncallService
import oncall.view.InputView
import oncall.view.OutputView

fun main() {
TODO("프로그램 구현")
OncallController.run(InputView, OutputView, OncallService)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package oncall.controller

import oncall.entity.Order
import oncall.service.OncallService
import oncall.view.InputView
import oncall.view.OutputView

object OncallController {

fun run(inputView: InputView, outputView: OutputView, oncallService: OncallService) {
val oncallDate = inputView.getOncallDate()
val (weekdayOrder: Order, holidayOrder: Order) = inputView.getOrder()
val oncallTable = oncallService.getOncallTable(
oncallDate, weekdayOrder = weekdayOrder, holidayOrder = holidayOrder
)
outputView.printOncallTable(oncallTable)
}
}
41 changes: 41 additions & 0 deletions kotlin-oncall/src/main/kotlin/oncall/entity/Order.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package oncall.entity

import oncall.exception.requireOncall

const val MAX_NICKNAME_SIZE = 5
const val MIN_ORDER_MEMBER = 5
const val MAX_ORDER_MEMBER = 35

class Order(private val order: List<String>) {
init {
requireOncall(order.all { it.length <= MAX_NICKNAME_SIZE }) { "닉네임은 최대 ${MAX_NICKNAME_SIZE}자 여야 합니다." }
requireOncall(order.size == order.distinct().size) { "중복된 이름이 있습니다." }
requireOncall(order.size in MIN_ORDER_MEMBER..MAX_ORDER_MEMBER) { "비상 근무자는 ${MIN_ORDER_MEMBER}명 이상 ${MAX_ORDER_MEMBER}명 이하여야 합니다. 비상 근무자 수 : ${order.size}" }
}

private val size = order.size
private var index = 0
private var queueMember: String? = null

fun getNextTurnMember(previousMember: String?) =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

식이 본문인 함수 사용 bb 인 것 같습니다~!

if (isQueueMemberTurn(previousMember)) {
val nextTurnMember = queueMember
queueMember = null
nextTurnMember
} else {
getNextTurnMember(previousMember, this.getNextMember())
}

private fun getNextTurnMember(previousMember: String?, nextMember: String) =
if (previousMember == nextMember) {
// 만약 다음 멤버와 바로 전 멤버가 같다면 큐에 넣고 그 다음 멤버를 순서로 올린다.
queueMember = nextMember
this.getNextMember()
} else {
nextMember
}

private fun isQueueMemberTurn(previousMember: String?) = queueMember != null && queueMember != previousMember

private fun getNextMember() = this.order[(index++) % this.size]
}
15 changes: 15 additions & 0 deletions kotlin-oncall/src/main/kotlin/oncall/exception/OncallException.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package oncall.exception

const val ERROR_PREFIX = "[ERROR] "

inline fun requireOncall(value: Boolean, lazyMessage: () -> Any) {
if (!value) {
throw OncallException(lazyMessage().toString())
}
}

class OncallException(message: String) : IllegalArgumentException() {
override val message = ERROR_PREFIX + message
}

fun printlnOncallException(message: String) = println(ERROR_PREFIX + message)
53 changes: 53 additions & 0 deletions kotlin-oncall/src/main/kotlin/oncall/model/OncallDate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package oncall.model

import java.time.DayOfWeek
import java.time.DayOfWeek.*
import java.time.Month

class OncallDate(val month: Month, private val startDayOfWeek: DayOfWeek) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JDK 표준 라이브러리가 있는지 몰랐네요..!! 유용하게 잘 쓰겠습니다~!! bb

val monthDay = month.minLength() // 2월은 항상 28일

private val holidayMap = getHolidayMap(startDayOfWeek)

private fun getHolidayMap(startDayOfWeek: DayOfWeek): Map<Int, Pair<DayOfWeek, DayType>> {
val holidayMap = mutableMapOf<Int, Pair<DayOfWeek, DayType>>()
for (day in 1..this.monthDay) {
val dayOfWeek = startDayOfWeek.plus((day - 1).toLong())
holidayMap[day] = Pair(dayOfWeek, isHoliday(dayOfWeek, day))
}
return holidayMap.toMap()
}

private fun isHoliday(dayOfWeek: DayOfWeek, day: Int) = when (dayOfWeek) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리턴 타입이 Boolean 이라고 생각되게 만드는 메서드 명인 것 같습니다~!

MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY ->
if (SPECIAL_HOLIDAY.contains(Pair(month.value, day))) {
DayType.WEEKDAY_HOLIDAY
} else {
DayType.WEEKDAY
}

SATURDAY, SUNDAY -> DayType.HOLIDAY
}

operator fun get(day: Int) = holidayMap[day]

companion object {
val SPECIAL_HOLIDAY = listOf(
Pair(1, 1),
Pair(3, 1),
Pair(5, 5),
Pair(6, 6),
Pair(8, 15),
Pair(10, 3),
Pair(10, 9),
Pair(12, 25)
)
}
}

enum class DayType {
WEEKDAY,
WEEKDAY_HOLIDAY,
HOLIDAY,
;
}
36 changes: 36 additions & 0 deletions kotlin-oncall/src/main/kotlin/oncall/service/OncallService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package oncall.service

import oncall.entity.Order
import oncall.exception.OncallException
import oncall.model.DayType
import oncall.model.OncallDate
import java.time.DayOfWeek

object OncallService {
fun getOncallTable(oncallDate: OncallDate, weekdayOrder: Order, holidayOrder: Order): String {
var previousMember: String? = null

return buildString {
for (day in 1..oncallDate.monthDay) {
val (dayOfWeek, dayType) = oncallDate[day] ?: throw OncallException("존재하지 않는 날짜입니다: ${day}일")
val nextMember = when (dayType) {
DayType.WEEKDAY -> weekdayOrder.getNextTurnMember(previousMember)
DayType.WEEKDAY_HOLIDAY, DayType.HOLIDAY -> holidayOrder.getNextTurnMember(previousMember)
}
previousMember = nextMember
append("${oncallDate.month.value}월 ${day}일 ${dayOfWeek.toKorean()}${if (dayType == DayType.WEEKDAY_HOLIDAY) "(휴일)" else ""} ${nextMember}\n")
}
}
}
}

private fun DayOfWeek.toKorean() = when (this) {
DayOfWeek.MONDAY -> "월"
DayOfWeek.TUESDAY -> "화"
DayOfWeek.WEDNESDAY -> "수"
DayOfWeek.THURSDAY -> "목"
DayOfWeek.FRIDAY -> "금"
DayOfWeek.SATURDAY -> "토"
DayOfWeek.SUNDAY -> "일"
else -> throw IllegalArgumentException()
}
51 changes: 51 additions & 0 deletions kotlin-oncall/src/main/kotlin/oncall/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package oncall.view

import camp.nextstep.edu.missionutils.Console
import oncall.entity.Order
import oncall.exception.printlnOncallException
import oncall.model.OncallDate
import java.time.DayOfWeek
import java.time.Month

object InputView {
fun getOncallDate() = tryGetUserInput {
print("비상 근무를 배정할 월과 시작 요일을 입력하세요> ")
Console.readLine().toOncallDate()
}

fun getOrder() = tryGetUserInput {
print("평일 비상 근무 순번대로 사원 닉네임을 입력하세요> ")
val weekdayOrder = Console.readLine().toOrder()
print("휴일 비상 근무 순번대로 사원 닉네임을 입력하세요>")
val holidayOrder = Console.readLine().toOrder()
Pair(weekdayOrder, holidayOrder)
}
}

private fun String.toOncallDate(): OncallDate {
val (monthString, startDayOfWeekString) = this.split(",")
return OncallDate(Month.of(monthString.toInt()), startDayOfWeekString.toDayOfWeek())
}

private fun String.toDayOfWeek() = when (this) {
"월" -> DayOfWeek.MONDAY
"화" -> DayOfWeek.TUESDAY
"수" -> DayOfWeek.WEDNESDAY
"목" -> DayOfWeek.THURSDAY
"금" -> DayOfWeek.FRIDAY
"토" -> DayOfWeek.SATURDAY
"일" -> DayOfWeek.SUNDAY
else -> throw IllegalArgumentException()
}

private fun String.toOrder() = Order(this.split(","))

private fun <T> tryGetUserInput(inputFunction: () -> T): T {
while (true) {
try {
return inputFunction()
} catch (ignore: Exception) {
printlnOncallException("유효하지 않은 입력 값입니다. 다시 입력해 주세요.")
}
}
}
7 changes: 7 additions & 0 deletions kotlin-oncall/src/main/kotlin/oncall/view/OutputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package oncall.view

object OutputView {
fun printOncallTable(oncallTable: String) {
println(oncallTable)
}
}