반디북
객체에서 함수로
Ch8
만혁

연습문제 8.1

fun sumOfOddSquaresAsSequence(numbers: Sequence<Long>): Long 
    = numbers.filter { it.isOdd() }.sumOf { it * it }

연습문제 8.2

data class NextFunction<T>(private val list: List<T>) : () -> T? {
    private var idx = 0
    override fun invoke(): T? {
        if (list.size <= idx) return null
 
        val item = list[idx]
        idx += 1
        return item
    }
}

연습문제 8.3

class ElevatorProjectionImpl(events: List<ElevatorEvent>) : ElevatorProjection {
    val map: Map<Int, ElevatorProjectRow> = events
            .groupBy { it.id }
            .mapValues { fold(it.value).toProjectionRow(it.key) }
 
    override fun allRows(): List<ElevatorProjectRow> {
        return map.values.toList()
    }
    override fun getRow(elevatorId: Int): ElevatorProjectRow? {
        return map[elevatorId]
    }
}
우석

연습문제 8.1

fun sumOfOddSquaresList(numbers: List<Long>): Long =
    numbers.filter { it.isOdd() }.sumOf { it * it }
 
fun sumOfOddSquaresSequence(numbers: Sequence<Long>): Long =
    numbers.filter { it.isOdd() }.sumOf { it * it }
 
fun sumOfOddSquaresForLoop(numbers: List<Long>): Long {
    var tot = 0L
    for (i in numbers) {
        if (i.isOdd()) tot += i * i
    }
    return tot
}

연습문제 8.2

data class NextFunction<T>(
    private val list: List<T>
): () -> T?  {
 
    private var index = 0
 
    override fun invoke(): T? {
        return if (index >= list.size)
            null
        else
            list[index++]
    }
}

연습문제 8.3

sealed class ElevatorEvent {
    abstract val elevatorId: Int
    abstract val eventId: Int
 
    data class ButtonPressed(override val elevatorId: Int, val floor: Int, override val eventId: Int) : ElevatorEvent()
    data class ElevatorMoved(override val elevatorId: Int, val fromFloor: Int, val toFloor: Int, override val eventId: Int) : ElevatorEvent()
    data class ElevatorBroken(override val elevatorId: Int, override val eventId: Int) : ElevatorEvent()
    data class ElevatorFixed(override val elevatorId: Int, override val eventId: Int) : ElevatorEvent()
}
 
 
sealed class ElevatorState {
 
    abstract val floor: Int
 
    data class DoorsOpenAtFloor(override val floor: Int) : ElevatorState()
    data class TravelingAtFloor(override val floor: Int) : ElevatorState()
    object OutOfOrder : ElevatorState() {
        override val floor: Int = 0
    }
}
 
data class ElevatorProjectionRow(val elevatorId: Int, val floor: Int, val state: ElevatorState)
 
fun foldEvents(events: List<ElevatorEvent>): ElevatorState =
    events.fold(DoorsOpenAtFloor(0) as ElevatorState) { state, event ->
        when (event) {
            is ButtonPressed ->
                if (state != DoorsOpenAtFloor(event.floor))
                    TravelingAtFloor(event.floor)
                else
                    state
 
            is ElevatorMoved -> DoorsOpenAtFloor(
                event.toFloor
            )
 
            is ElevatorBroken -> OutOfOrder
            is ElevatorFixed -> DoorsOpenAtFloor(0) // assume elevator goes back to ground floor when fixed
 
        }
    }
 
 
interface ElevatorProjection {
    fun allRows(): List<ElevatorProjectionRow>
    fun getRow(elevatorId: Int): ElevatorProjectionRow?
}
 
class ElevatorProjectionInMemory(events: List<ElevatorEvent>) : ElevatorProjection {
    val stateMap: Map<Int, ElevatorProjectionRow> =
        events.sortedBy { it.eventId }
            .groupBy { it.elevatorId }
            .mapValues { foldEvents(it.value).toProjectionRow(it.key) }
 
    override fun allRows(): List<ElevatorProjectionRow> = stateMap.values.toList()
 
 
 
    override fun getRow(elevatorId: Int): ElevatorProjectionRow? = stateMap[elevatorId]
}
 
private fun ElevatorState.toProjectionRow(elevatorId: Int) =
    ElevatorProjectionRow(elevatorId, this.floor, this)