01 티켓 판매 어플리케이션 구현하기

import java.time.LocalDateTime

class Invitation {
    private var `when`: LocalDateTime? = null
}
class Ticket {
    var fee: Long = 0L
        private set
}
class Bag(
    private val invitation: Invitation? = null,
    private var amount: Long
) {
    var ticket: Ticket? = null

    val hasInvitation: Boolean
        get() = invitation != null

    val hasTicket: Boolean
        get() = ticket != null

    fun minusAmount(amount: Long) {
        this.amount -= amount
    }

    fun plusAmount(amount: Long) {
        this.amount += amount
    }
}
class Audience(val bag: Bag)
class TicketOffice(private var amount: Long, vararg tickets: Ticket) {
    private val tickets: List<Ticket> = tickets.toList()

    val ticket: Ticket?
        get() = tickets.getOrNull(0)

    fun minusAmount(amount: Long) {
        this.amount -= amount
    }

    fun plusAmount(amount: Long) {
        this.amount += amount
    }

}
class TicketSeller(val ticketOffice: TicketOffice)
class Theater(private val ticketSeller: TicketSeller) {

    fun enter(audience: Audience) {
        val ticket = ticketSeller.ticketOffice.ticket ?: return
        if (audience.bag.hasInvitation) {
            audience.bag.ticket = ticket
        } else {
            val fee = ticket.fee
            audience.bag.minusAmount(fee)
            audience.bag.ticket = ticket
            ticketSeller.ticketOffice.plusAmount(fee)
        }
    }
}

02 무엇이 문제인가

소프트웨어 모듈의 목적은

  1. 제대로 동작하는 코드
  2. 변경하기 쉬운 코드
  3. 이해하기 쉬운 코드

예상을 빗나가는 코드

enter 함수 안에서 너무 많은 클래스의 역할들을 알고 있어야 하기 때문에 코드 작성자와 추후 수정하는 사람 모두 큰 부담이다.

또한 Audience와 TicketSeller를 변경할 경우 Theater#enter도 변경될 가능성이 높다.