[Kotlin 문법 심화] 팀과제 - 키오스크 Lv2.

0
post-thumbnail

🍥구현 기능

  • 필요한 클래스들을 설계하여 구현하기

🍥구현하기

  • 하나의 메뉴 아이템을 나타내는 클래스
  • 프로퍼티:
    • name
      메뉴 아이템의 이름(ex. "ShackBurger")
    • cost
      메뉴 아이템의 가격(ex. 6900)
    • description
      메뉴 아이템의 설명(ex. "토마토, 양상추, 쉑소스가 토핑된 치즈버거")
 class MenuItem(val name:String, val cost: Int, val description: String?)
  • 여러 개의 메뉴 아이템을 나타내는 클래스
  • 프로퍼티:
    • colloctionName
      메뉴 아이템 목록의 이름(ex. "Burger")
    • collectionDescription
      메뉴 아이템 목록의 설명
      (ex. "100% 앵거스 비프 통살을 다져 만든 패티와 쫄깃한 식감의 포테이토 번을 사용한 버거")
    • menuItemList
      메뉴 아이템 목록
  • 메소드:
    • getSize():Int
      메뉴 아이템 목록의 크기를 반환
    • isEmpty():Boolean
      메뉴 아이템 목록이 비어있는지 true/false 반환
    • addMenuItem(menuItem: MenuItem)
      메뉴 아이템을 메뉴 아이템 목록에 추가
    • removeMenuItemAt(index: Int)
      메뉴 아이템 목록에서 index 위치의 메뉴 아이템 삭제
    • getMenuItemAt(index:Int):MenuItem
      메뉴 아이템 목록에서 index 위치의 메뉴 아이템 반환
    • clearMenuItemList()
      메뉴 아이템 목록 초기화
    • getCostSum():Int
      메뉴 아이템 목록의 메뉴 아이템들의 가격 총 합 반환
    • printMenuItems()
      메뉴 아이템 목록의 메뉴 아이템들의 정보 출력
      (출력 형식: 번호. 메뉴 아이템 이름 - 메뉴 아이템 가격 - 메뉴 아이템 설명)
class MenuItemCollection(){
    var collectionName:String? = null
    var collectionDescription:String? = null
    private var menuItemList = arrayOf<MenuItem>()

    fun getSize():Int = menuItemList.size
    
    fun isEmpty():Boolean = menuItemList.isEmpty()
    
    fun addMenuItem(menuItem: MenuItem){
        menuItemList += menuItem
    }
    
    fun removeMenuItemAt(index: Int){
        menuItemList = menuItemList.filterIndexed{i, menuItem -> i != index}.toTypedArray()
    }
    
    fun getMenuItemAt(index: Int):MenuItem{
        return menuItemList[index]
    }
    
    fun clearMenuItemList() {
        menuItemList = arrayOf<MenuItem>()
    }
    
    fun getCostSum(): Int {
        var costSum = 0
        for(menuItem in menuItemList) costSum += menuItem.cost
        return costSum
    }

    fun printMenuItems(){
        for(i in 0 until menuItemList.size){
            var printString = "${i+1}. "
            menuItemList[i].apply {
                printString +=  "${this.name} - ${this.cost}"
                if(this.description != null) printString += " - ${this.description}"
            }
            println(printString)
        }
    }
}

MyMenu 클래스

  • 키오스크에서 사용되는 전체 메뉴를 나타내는 클래스
  • 프로퍼티:
    • burgerMenuItemCollection
      버거 카테고리의 메뉴 아이템들을 담은 MenuItemCollection
    • frozenCustardMenuItemCollection
      프로즌 커스터드 카테고리의 메뉴 아이템들을 담은 MenuItemCollection
    • drinksMenuItemCollection
      음료 카테고리의 메뉴 아이템들을 담은 MenuItemCollection
    • beerMenuItemCollection
      맥주 카테고리의 메뉴 아이템들을 담은 MenuItemCollection
    • myMenuCollections
      네 가지 카테고리의 MenuItemCollection들의 목록
      = listOf(burgerMenuItemCollection, frozenCustardMenuItemCollection, drinksMenuItemCollection, beerMenuItemCollection)
  • 메소드:
    • initBurgerMenuItemCollection()
      burgerMenuItemCollection의 정보 저장
    • initFrozenCustardMenuItemCollection()
      frozenCustardMenuItemCollection의 정보 저장
    • initDrinksMenuItemCollection()
      drinksMenuItemCollection의 정보 저장
    • initBeerMenuItemCollection()
      beerMenuItemCollection의 정보 저장
    • printMyMenuCollections()
      myMenuCollections의 정보 출력
      (출력 형식: 번호. MenuItemCollection 이름 - MenuItemCollection 설명)
class MyMenu(){
    val burgerMenuItemCollection = MenuItemCollection()
    val frozenCustardMenuItemCollection = MenuItemCollection()
    val drinksMenuItemCollection = MenuItemCollection()
    val beerMenuItemCollection = MenuItemCollection()

    val myMenuCollections by lazy{
        listOf(burgerMenuItemCollection,
            frozenCustardMenuItemCollection,
            drinksMenuItemCollection,
            beerMenuItemCollection)
    }

    init{
        initBurgerMenuItemCollection()
        initFrozenCustardMenuItemCollection()
        initDrinksMenuItemCollection()
        initBeerMenuItemCollection()
    }

    fun printMyMenuCollections(){
        for(i in 0 until myMenuCollections.size){
            var printString = "${i+1}. "
            myMenuCollections[i].apply{
                printString += "${this.collectionName!!}"
                if(this.collectionDescription != null) printString += " - ${this.collectionDescription}"
            }
            println(printString)
        }
    }

    private fun initBurgerMenuItemCollection() {
        burgerMenuItemCollection.apply{
            collectionName = "Burgers"
            collectionDescription = "100% 앵거스 비프 통살을 다져 만든 패티와 쫄깃한 식감의 포테이토 번을 사용한 버거"
            addMenuItem(MenuItem("Shack Burger", 6900,"토마토, 양상추, 쉑소스가 토핑된 치즈버거"))
            addMenuItem(MenuItem("Smoke Burger", 8900,"애플 우드 칩으로 훈연한 베이컨, 매콤한 체리 페퍼에 쉑소스가 토핑된 치즈버거"))
            addMenuItem(MenuItem("Shroom Burger", 9400,"몬스터 치즈와 체다 치즈로 속을 채우고 바삭하게 튀겨낸 포토벨로 버섯 패티에 양상추, 토마토, 쉑소스를 올린 베지테리안 버거"))
            addMenuItem(MenuItem("Shack Shack Burger", 12400,"슈룸 버거와 쉑버거의 맛을 한번에 즐길 수 있는 메뉴"))
            addMenuItem(MenuItem("Cheese Burger", 6900,"포테이토 번과 비프 패티, 치즈가 토핑된 치즈버거"))
            addMenuItem(MenuItem("Hamburger", 5400,"포테이토 번과 비프 패티를 기본으로 신선한 양상추, 토마토 피클, 양파 토핑을 취향에 따라 선택할 수 있는 버거"))
        }
    }
    private fun initFrozenCustardMenuItemCollection() {
        frozenCustardMenuItemCollection.apply{
            collectionName = "Frozen Custard"
            collectionDescription = "매일 매장에서 신선하게 직접 만드는 부드럽고 진한 맛의 쫀득한 아이스크림"
            addMenuItem(MenuItem("Shakes", 5900, "바닐라, 초콜렛, 솔티드 카라멜, 블랙&화이트, 스트로베리, 피넛버터, 커피"))
            addMenuItem(MenuItem("Shake of the Week", 6500, "특별한 커스터드 플레이버"))
            addMenuItem(MenuItem("Red Bean Shake", 6500, "신선한 커스터드와 함께 우유와 레드빈이 블렌딩 된 시즈널 쉐이크"))
            addMenuItem(MenuItem("Floats", 5900, "루트 비어, 퍼플 카우, 크림시클"))
            addMenuItem(MenuItem("Cups & Cones", 4900, "바닐라, 초콜렛, Flavor of the Week"))
            addMenuItem(MenuItem("Concretes", 5900, "쉐이크쉑의 쫀득한 커스터드와 다양한 믹스-인의 조합"))
        }
    }
    private fun initDrinksMenuItemCollection(){
        drinksMenuItemCollection.apply {
            collectionName = "Drinks"
            addMenuItem(MenuItem("Shack-made Lemonade", 3900, "매장에서 직접 만드는 상큼한 레몬에이드"))
            addMenuItem(MenuItem("Fresh Brewed Iced Tea", 3400, "직접 유기농 홍차를 우려낸 아이스티"))
            addMenuItem(MenuItem("Fifty/Fifty", 3500, "레몬에이드와 아이스티의 만남"))
            addMenuItem(MenuItem("Fountain Soda", 2700, "코카콜라, 코카콜라 제로, 스프라이트, 환타 오렌지, 환타 그레이프"))
            addMenuItem(MenuItem("Abita Root Beer", 4400, "청량감 있는 독특한 미국식 무알콜 탄산음료"))
            addMenuItem(MenuItem("Bottled Water", 1000, "지리산 암반대수층으로 만든 프리미엄 생수"))
        }
    }
    private fun initBeerMenuItemCollection(){
        beerMenuItemCollection.apply {
            collectionName = "Beer"
            addMenuItem(MenuItem("ShackMeister Ale", 9800, "쉐이크쉑 버거를 위해 뉴욕 브루클린 브루어리에서 특별히 양조한 에일 맥주"))
            addMenuItem(MenuItem("Magpie Brewing Co.", 6800, null))
            addMenuItem(MenuItem("The Hand and Malt", 6800, null))
        }
    }

}

FirstScreen 클래스

  • 요구사항 0. 첫 화면을 구현한 클래스
  • 메소드:
    • run()
      첫 화면 실행
    • getInput()
      첫 화면에 알맞는 입력값 받기
      (가능한 입력 값: 아무 키나 입력받을 수 있다)
    • printScreen()
      첫 화면 출력
class FirstScreen {
    fun run(){
        getInput()
    }
    
    private fun getInput(){
        printScreen()
        readLine()
    }

    private fun printScreen(){
        println("[첫 화면]")
        println("주문을 시작하려면 아무 키나 입력하세요...")
        print("->")
    }
}

TakeOutScreen 클래스

  • 요구사항 1. 먹고 가기/포장하기 화면을 구현한 클래스
  • 메소드:
    • run():String
      먹고 가기/포장하기 화면 실행 후 입력값 반환
    • getInput():String
      먹고 가기/포장하기 화면에 알맞는 입력 받기
      (가능한 입력 값: 1, 2, q)
    • printScreen()
      먹고가기/포장하기 화면 출력
class TakeOutScreen {
    fun run():String{
        return getInput()
    }

    private fun getInput():String{
        val possibleInputs = listOf("1", "2", "q")
        var input = ""
        while(true){
            printScreen()
            input = readLine()?.toString() ?: ""
            if(possibleInputs.contains(input)) break
            else println("잘못된 입력입니다.")
        }
        return input
    }

    private fun printScreen(){
        println("[먹고 가기/포장하기 화면]")
        println("1. 먹고 가기")
        println("2. 포장하기")
        println("q. 주문 종료 - 주문을 종료하고 첫 화면으로 돌아갑니다.")
        print("->")
    }
}

MainScreen 클래스

  • 요구사항 2. 메인 화면을 구현한 클래스
  • 메소드:
    • run():String
      메인 화면 실행 후 입력값 반환
    • getInput():String
      메인 화면에 알맞는 입력값 받기
      (가능한 입력 값: 메뉴 카테고리의 번호, c, o, b, q)
    • printScreen()
      메인 화면 출력
class MainScreen() {
    fun run():String{
        return getInput()
    }

    private fun getInput():String{
        var possibleInputs = arrayOf("c", "o", "b", "q")
        for (i in 1..MyKiosk.myMenu.myMenuCollections.size)
            possibleInputs += i.toString()

        var input = ""
        while(true){
            printScreen()
            input = readLine()?.toString() ?: ""
            if(possibleInputs.contains(input)) break
            else println("잘못된 입력입니다.")
        }
        return input
    }
    
    private fun printScreen(){
        println("[메인 화면]")
        println("주문할 메뉴의 카테고리를 선택하세요.")
        MyKiosk.myMenu.printMyMenuCollections()
        println("c: 장바구니 - 장바구니 화면으로 이동합니다.")
        println("o: 주문하기 - 주문하기 화면으로 이동합니다.")
        println("b: 뒤로 가기 - 먹고 가기/포장하기 화면으로 돌아갑니다.")
        println("q: 주문 종료 - 주문을 종료하고 첫 화면으로 돌아갑니다.")
        print("->")
    }
}

SelectMenuScreen 클래스

  • 요구사항 3. 메뉴 선택 화면을 구현한 클래스
  • 프로퍼티:
    • menuItemCollection
      사용자가 선택한 카테고리의 메뉴 아이템들을 담은 MenuItemCollection
  • 메소드:
    • run(menuResult:String)
      사용자가 선택한 카테고리의 번호를 매개변수로 받아와, 메뉴 선택 화면 실행
      사용자가 선택한 메뉴 아이템 항목을 장바구니에 추가
    • getInput():String
      메뉴 선택 화면에 알맞는 입력값 받기
      (가능한 입력 값: 사용자가 선택한 카테고리에 속한 메뉴 아이템의 번호, b)
    • printScreen()
      메뉴 선택 화면 출력
class SelectMenuScreen {
    var menuItemCollection: MenuItemCollection? = null

    fun run(menuResult:String){
        menuItemCollection =  MyKiosk.myMenu.myMenuCollections[menuResult.toInt()-1]

        while(true){
            val input = getInput()
            if(input == "b") return

            //선택한 메뉴 장바구니에 추가
            val selectedMenuItem = menuItemCollection!!.getMenuItemAt(input.toInt()-1)
            MyKiosk.shoppingCart.addMenuItem(selectedMenuItem)
            println("장바구니에 ${selectedMenuItem.name}이 추가되었습니다.")
        }
    }

    private fun getInput():String{
        var possibleInputs = arrayOf("b")
        for(i in 1..menuItemCollection!!.getSize()) possibleInputs += i.toString()

        var input = ""
        while(true){
            printScreen()
            input = readLine()?.toString() ?: ""
            if(possibleInputs.contains(input)) break
            else println("잘못된 입력입니다.")
        }
        return input
    }

    private fun printScreen(){
        println("[${menuItemCollection!!.collectionName} 메뉴 선택 화면]")
        println("주문할 메뉴를 선택하세요.")
        menuItemCollection!!.printMenuItems()
        println("b: 뒤로 가기 - 메인 화면으로 돌아갑니다.")
        print("->")
    }
}

ShoppingCartScreen 클래스

  • 요구사항 4. 장바구니 화면을 구현한 클래스
  • 프로퍼티:
    • isShoppingCartEmpty
      장바구니가 비어있으면 true, 비어있지 않으면 false
    • deleteFromShoppingCart
      DeleteFromShoppingCart 클래스의 인스턴스
  • 메소드:
    • run()
      장바구니 화면 실행
      입력값이 d라면, 장바구니에서 항목 삭제 실행
    • getInput():String
      장바구니 화면에 알맞는 입력값 받기
      (가능한 입력 값: b, (장바구니가 비어있지 않은 경우)d)
    • printScreen()
      장바구니 화면 출력
    • printCostSum()
      장바구니 속 메뉴 아이템 가격의 총 합 출력

DeleteFromShoppingCart 클래스

  • 장바구니에서 항목 삭제 화면을 구현한 클래스
  • 메소드:
    • run()
      장바구니에서 항목 삭제 화면 실행
      사용자가 선택한 메뉴 아이템 항목을 장바구니에서 삭제
    • getInput():String
      장바구니에서 항목을 삭제 화면에 알맞는 입력값 받기
      (가능한 입력 값: 장바구니 속 메뉴 아이템 항목의 번호)
    • printScreen()
      장바구니에서 항목 삭제 화면 출력
class ShoppingCartScreen {

    var isShoppingCartEmpty = true
    val deleteFromShoppingCart = DeleteFromShoppingCart()
    fun run(){
        var input = ""
        while(true) {
            isShoppingCartEmpty = MyKiosk.shoppingCart.isEmpty()
            input = getInput()
            if(input == "b") return
            else if(input == "d") deleteFromShoppingCart.run()
        }
    }
    private fun getInput():String{
        var possibleInputs = arrayOf("b")
        if(!isShoppingCartEmpty) possibleInputs += "d"

        var input = ""
        while(true){
            printScreen()
            input = readLine()?.toString() ?: ""
            if(possibleInputs.contains(input)) break
            else println("잘못된 입력입니다.")
        }
        return input
    }
    private fun printScreen(){
        println("[장바구니 화면]")
        if(isShoppingCartEmpty) println("장바구니가 비었습니다.")
        else MyKiosk.shoppingCart.printMenuItems()
        if(!isShoppingCartEmpty) printCostSum()
        println("b: 뒤로 가기 - 메인 화면으로 돌아갑니다.")
        if(!isShoppingCartEmpty) println("d: 장바구니에서 삭제 - 선택한 항목을 장바구니에서 삭제합니다.")
        print("->")
    }

    private fun printCostSum(){
        var costSum = MyKiosk.shoppingCart.getCostSum()
        println("-----가격 총 합: ${costSum}")
    }

    class DeleteFromShoppingCart() {
        fun run() {
            val input = getInput()
            MyKiosk.shoppingCart.removeMenuItemAt(input.toInt() - 1)
            println("선택한 항목이 삭제되었습니다.")
        }

        private fun getInput(): String {
            var possibleInputs = arrayOf<String>()
            for (i in 1..MyKiosk.shoppingCart.getSize()) possibleInputs += i.toString()

            var input = ""
            while (true) {
                printScreen()
                input = readLine()?.toString() ?: ""
                if (possibleInputs.contains(input)) break
                else println("잘못된 입력입니다.")
            }
            return input
        }

        private fun printScreen() {
            println("[장바구니에서 항목 삭제하기]")
            println("삭제할 항목의 번호를 입력하세요.")
            print("->")
        }
    }
}

OrderScreen 클래스

  • 요구사항 5. 주문하기 화면을 구현한 클래스
  • 프로퍼티:
    • isShoppingCartEmpty
      장바구니가 비어있으면 true, 비어있지 않으면 false
  • 메소드:
    • run():Boolean
      주문하기 화면 실행
      사용자가 뒤로가기를 선택했다면 false, 결제하기를 선택했다면 true 반환
    • getInput():String
      주문하기 화면에 알맞는 입력값 받기
      (가능한 입력 값: b, (장바구니가 비어있지 않은 경우)q)
    • printScreen()
      주문하기 화면 출력
    • printCostSum()
      장바구니 속 메뉴 아이템 가격의 총 합 출력
class OrderScreen {
    var isShoppingCartEmpty = true
    
    fun run():Boolean{
        isShoppingCartEmpty = MyKiosk.shoppingCart.isEmpty()

        val input = getInput()
        if(input == "b") return false
        if(input == "p") return true
        return false //error
    }

    private fun getInput():String{
        var possibleInputs = arrayOf("b")
        if(!isShoppingCartEmpty) possibleInputs += "p"

        var input = ""
        while(true){
            printScreen()
            input = readLine()?.toString() ?: ""
            if(possibleInputs.contains(input)) break
            else println("잘못된 입력입니다.")
        }
        return input
    }
    private fun printScreen(){
        println("[주문하기 화면]")
        println("-----${if(MyKiosk.isTakeOut)"포장하기" else "먹고 가기"}")
        if(isShoppingCartEmpty) println("장바구니가 비었습니다.")
        else MyKiosk.shoppingCart.printMenuItems()
        if(!isShoppingCartEmpty) printCostSum()
        println("b: 뒤로 가기 - 메인 화면으로 돌아갑니다.")
        if(!isShoppingCartEmpty) println("p: 결제하기 - 주문 완료 화면으로 이동합니다.")
        print("->")
    }

    private fun printCostSum(){
        var costSum = MyKiosk.shoppingCart.getCostSum()
        println("-----가격 총 합: ${costSum}")
    }
}

OrderCompleteScreen 클래스

  • 요구사항 6. 주문 완료 화면을 구현한 클래스
  • 메소드:
    • run()
      주문 완료 화면 실행
    • printScreen()
      주문 완료 화면 출력
class OrderCompleteScreen {
    fun run(){
        printScreen()
    }
    
    private fun printScreen(){
        println("[주문 완료 화면]")
        println("주문이 완료되었습니다.")
        println("잠시 후 첫 화면으로 이동합니다...")
    }
}

MyKiosk 클래스

  • 키오스크가 실행되는 로직을 구현한 클래스
  • 싱글톤 패턴으로 구현
  • companion object 속 프로퍼티:
    • myMenu
      MyMenu 클래스의 인스턴스
    • shoppingCart
      장바구니, 사용자가 선택한 메뉴 아이템들을 담은 MenuItemCollection
    • isTakeOut
      사용자가 먹고 가기를 선택했다면 false, 포장하기를 선택했다면 true
  • 프로퍼티:
    • firstScreen
    • takeOutScreen
    • mainScreen
    • selectMenuScreen
    • shoppingCartScreen
    • orderScreen
    • orderCompleteScreen
  • 메소드:
    • run()
      키오스크 프로그램 실행 (무한 반복)
class MyKiosk private constructor(){

    //각 화면 구현
    private val firstScreen = FirstScreen()
    private val takeOutScreen = TakeOutScreen()
    private val mainScreen = MainScreen()
    private val selectMenuScreen = SelectMenuScreen()
    private val shoppingCartScreen = ShoppingCartScreen()
    private val orderScreen = OrderScreen()
    private val orderCompleteScreen = OrderCompleteScreen()

    companion object{
        //싱글톤 패턴
        private var instance:MyKiosk? = null
        fun newInstance():MyKiosk{
            if(instance == null) instance = MyKiosk()
            return instance!!
        }

        val myMenu = MyMenu()
        val shoppingCart = MenuItemCollection()
        var isTakeOut:Boolean = false
    }

    //키오스크 프로그램 실행 (무한 반복)
    fun run(){
        //0. 첫 화면
        firstLoop@ while(true){
            firstScreen.run()

            //1. 먹고 가기/포장하기 화면
            takeOutLoop@ while(true) {
                //장바구니 초기화
                shoppingCart.clearMenuItemList()

                val takeOutResult = takeOutScreen.run()
                when(takeOutResult) {
                    "1" -> isTakeOut = false
                    "2" -> isTakeOut = true
                    "q" -> continue@firstLoop //0. 첫 화면
                }

                //2. 메인 화면
                mainLoop@ while (true) {
                    val mainResult = mainScreen.run()
                    when (mainResult) {
                        "c" -> shoppingCartScreen.run() //4. 장바구니 화면
                        "o" -> {
                            //5. 주문하기 화면
                            val isOrderComplete = orderScreen.run()
                            if(isOrderComplete) break@mainLoop //6. 주문 완료 화면
                        }
                        "b" -> continue@takeOutLoop //1. 먹고가기/포장하기 화면
                        "q" -> continue@firstLoop //0. 첫 화면

                        else -> selectMenuScreen.run(mainResult) //3. 메뉴 선택 화면
                    }
                }
                //6. 주문 완료 화면
                orderCompleteScreen.run()
                continue@firstLoop
            }
        }

    }
}

Kiost.kt

fun main() {
    val myKiosk = MyKiosk.newInstance()
    myKiosk.run()
}
profile
Be able to be vulnerable, in search of truth

0개의 댓글