코틀린 개인 과제

키오스크 제작

songyooho 2024. 6. 13. 18:34

1. 개요

1)클래스

-Menu: 모든 메뉴를 통합해 관리하기위한 추상 클래스

 

-Pizza: 피자 메뉴를 관리하기 위한 추상클래스, Menu상속

-Drink: 음료 메뉴를 관리하기 위한 추상클래스, Menu상속

-Side: 사이드 메뉴를 관리하기 위한 추상클래스, Menu상속

 

-CheesePizza

-PepperoniPizza

-PotatoPizza

=> Pizza상속

 

-Cola

-Beer

-Cider

=>Drink상속

 

-FrenchFries

-GrilledChicken

=>Side상속

 

2)main.kt

-초기값 구성

-키오스트 화면 구성

-일부 쓰레드 실행

-기능 구현

 

3)전체적인 부분

-try-catch로 입력받을때 생기는 예외처리

 

2. 설명

1)Menu

abstract class Menu() {
    abstract var flag:Boolean //메뉴가 주문에 담겨있는지 여부 체크
    abstract fun displayInfo() //메뉴 정보 출력
    abstract fun orderList() //메뉴 주문 정보 출력
    abstract fun order():Int //주문하기
    abstract fun changeOrder():Int //담겨있는 주문정보 수정
}

 

2)Pizza

abstract class Pizza:Menu() {
    abstract val name:String
    abstract val price:Int
    var order=arrayOf(0,0,0) //사이즈 별로 첫번째가 스몰, 두번째가 레귤러, 세번째가 라지
    override var flag=false //주문 수량이 없으면 false

    override fun displayInfo() {
        println("이름: ${name}, 가격: ${price}")
    }

    override fun orderList() {
        if(!flag) return
        println("이름: ${name}, 주문수: 스몰-${order[0]} / 레귤러-${order[1]} / 라지-${order[2]}")
    }

    override fun order():Int {
        var sizesTmp:Int?
        var num:Int?
        while(true){
            try {
                println("\n[Size]\n")
                println("1.스몰\n2.레귤러\n3.라지\n0.메인메뉴로")
                sizesTmp= readLine()?.toString()?.toInt()
                if(sizesTmp==0) return 0

                if(sizesTmp==null||sizesTmp !in 0..3){
                    println("다시 입력해주세요")
                    continue
                }

                println("수량을 입력해 주세요")
                num= readLine()?.toString()?.toInt()
                if(num==null||num<=0){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }

            val tmpSize=when(sizesTmp){
                1->"스몰"
                2->"레귤러"
                else->"라지"
            }
            println("주문완료: 사이즈-${tmpSize} / 수량-${num}")
            flag=true

            when(sizesTmp){
                1 ->order[0]+=num
                2 ->order[1]+=num
                else ->order[2]+=num
            }
            break
        }
        return num!!*price
    }

    override fun changeOrder():Int {
        var select:Int?
        var num:Int?
        println("수정을 원하는 사이즈를 입력해주세요\n1.스몰    2.레귤러    3.라지")
        while (true){
            try {
                select= readLine()?.toString()?.toInt()
                if(select==null||select !in 1..3){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }
            break
        }
        println("수량을 입력해주세요(정수로 입력)")
        while (true){
            try {
                num= readLine()?.toString()?.toInt()
                if(num==null||num+order[select!!-1]<0){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }
            break
        }
        order[select!!-1]+=num as Int
        if(order.sum()==0){
            flag=false
        }
        return num* price


    }


}

-Menu단계에서 기획했던 의도대로 상속받아 오버라이드 해줌.

-피자의 경우 주문시 사이즈 결정메뉴가 있으므로 그에 맞춰 order를 size 3짜리 배열로 만들고 order()와 changeOrder()에서 사이즈결정 부분을 추가

 

3)Drink

abstract class Drink:Menu() {
    abstract val name:String
    abstract val price:Int
    var order=arrayOf(0,0) //얼음유무로. 앞이 얼음있는것 뒤가 얼음 없는것
    override var flag=false //주문 수량이 없으면 false

    override fun displayInfo() {
        println("이름: ${name}, 가격: ${price}")
    }

    override fun orderList() {
        if(!flag) return
        println("이름: ${name}, 주문수: 얼음 있음-${order[0]} / 얼음 없음-${order[1]}")
    }

    override fun order():Int {
        var ice:Int?
        var num:Int?
        while(true){
            try {
                println("얼음을 넣으시겠습니까?\n1.Yes\n2.No\n0.메인메뉴로")
                ice= readLine()?.toString()?.toInt()
                if(ice==0) return 0

                if(ice==null||(ice!=1&&ice!=2)){
                    println("다시 입력해주세요")
                    continue
                }

                println("수량을 입력해 주세요")
                num= readLine()?.toString()?.toInt()
                if(num==null||num<=0){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }

            println("주문완료: 얼음 ${if(ice==1) "넣음" else "안 넣음"} / 수량-${num}")
            flag=true

            when(ice){
                0 ->order[0]+=num
                else ->order[1]+=num
            }
            break
        }
        return num!!*price
    }

    override fun changeOrder():Int {
        var select:Int?
        var num:Int?
        println("수정을 원하는 타입을 입력해주세요\n1.얼음 있음    2.얼음 없음")
        while (true){
            try {
                select= readLine()?.toString()?.toInt()
                if(select==null||select !in 1..2){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }
            break
        }
        println("수량을 입력해주세요(정수로 입력)")
        while (true){
            try {
                num= readLine()?.toString()?.toInt()
                if(num==null||num+order[select!!-1]<0){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }
            break
        }
        order[select!!-1]+=num as Int
        if(order.sum()==0){
            flag=false
        }

        return num*price

    }

}

-Menu단계에서 기획했던 의도대로 상속받아 오버라이드 해줌.

-Pizza와 유사하게 오버라이드 해주나 음료의 경우 사이즈대신 얼음 유무결정 요소가 있으므로 order를 사이즈2짜리 배열로 만들고 order()와 changeOrder()에서 얼음유무 선택지를 만들어줌

 

4)Side

abstract class Side:Menu() {
    abstract val name:String
    abstract val price:Int
    var order:Int=0
    override var flag=false //주문 수량이 없으면 false

    override fun displayInfo() {
        println("이름: ${name}, 가격: ${price}")
    }

    override fun orderList() {
        if(!flag) return
        println("이름: ${name}, 주문수: ${order}")
    }

    override fun order():Int {
        var num:Int?
        while(true){
            try {
                println("수량을 입력해 주세요(0.메인메뉴로)")
                num= readLine()?.toString()?.toInt()
                if(num==0) return 0
                if(num==null||num<=0){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }

            println("주문완료: 수량-${num}")
            order+=num
            flag=true
            break
        }
        return num!!*price
    }

    override fun changeOrder():Int {
        var select:Int?
        var num:Int?

        println("수량을 입력해주세요(정수로 입력)")
        while (true){
            try {
                num= readLine()?.toString()?.toInt()
                if(num==null||num+order<0){
                    println("다시 입력해주세요")
                    continue
                }
            }catch (e:Exception){
                println("다시 입력해주세요")
                continue
            }
            break
        }
        order+=num as Int
        if(order==0){
            flag=false
        }

        return num*price

    }
}

-Menu단계에서 기획했던 의도대로 상속받아 오버라이드 해줌.

-Side의 경우 추가 결정 요소가 없으므로 order()와 changeOrder()에서 수량만 받게 함.

 

5)나머지 클래스: 각각이 상속받은 클래스에 대해 이름과 가격만 오버라이드해주도록 함.

 

6)main.kt

<1>fun init(menu:ArrayList<Menu>)

fun init(menu:ArrayList<Menu>){
    menu+=Cola()
    menu+=Cider()
    menu+=Beer()
    menu+=FrenchFries()
    menu+=GrilledChicken()
    menu+=CheesePizza()
    menu+=PepperoniPizza()
    menu+=PotatoPizza()
}

-메뉴들의 초기값을 설정해 리스트에 담아두는 함수

-시작하거나 장바구니에 담은 메뉴를 모두 없애거나 결제시 실행

 

<2>fun orderMenu(menu: ArrayList<Menu>, category: Int, total:Array<Int>)

fun orderMenu(menu: ArrayList<Menu>, category: Int, total:Array<Int>){
    if(category==4){
        return chageOrder(menu,total)
    }

    val tmpMenu=ArrayList<Menu>()

    for(i in menu){
        if(category==1){
            if(i is Pizza){
                tmpMenu+=i
            }
        }else if(category==2){
            if(i is Drink){
                tmpMenu+=i
            }
        }else if(category==3){
            if(i is Side){
                tmpMenu+=i
            }
        }
    }

    val title=when(category){
        1->"[Pizza]"
        2->"[Drink]"
        else->"[Side]"
    }

    println("\n${title}\n")
    for(i in tmpMenu.indices) {
        print("${i+1}." )
        tmpMenu[i].displayInfo()
    }
    println("0.뒤로가기")

    var orders:Int?
    while (true){
        try{
            orders= readLine()?.toString()?.toInt()
            if(orders!=null&&orders==0) return
            if(orders==null||orders !in 1..tmpMenu.size){
                println("다시 입력해주세요")
                continue
            }
        }catch (e:Exception){
            println("다시 입력해주세요")
            continue
        }
        break
    }

    total[0]+=tmpMenu[orders!!-1].order()


}

-세부메뉴를 보여주는 함수. 메뉴선택시 클래스에 있는 함수인 order()함수를 실행하며 총 주문 금액을 올려준다.

 

<3>fun chageOrder(menu: ArrayList<Menu>,total: Array<Int>)

fun chageOrder(menu: ArrayList<Menu>,total: Array<Int>){
    if(!checkOrder(menu,total,true)) return
    println("수정을 원하는 메뉴를 선택해주세요")
    var select:Int?

    var size=menu.filter{it.flag==true}.size
    while (true){
        try {
            select= readLine()?.toString()?.toInt()
            if(select!=null&&select==0) return
            if(select==null||select !in -1..size){
                println("다시 입력해주세요")
                continue
            }
        }catch (e:Exception){
            println("다시 입력해주세요")
            continue
        }
        break
    }

    if(select==-1){
        menu.clear()
        init(menu)
        total[0]=0
    }else{
        for(i in menu){
            if(i.flag){
                size--
            }
            if(size==0){
                total[0]+=i.changeOrder()
                break
            }
        }
    }
}

-주문 확인 및 수정을 원할시 실행되는 함수

-담아둔 주문의 목록을 보여주고 선택시 클래스에 포함된 changeOrder()함수를 실행한다.

-이후 총 주문 금액 변경

 

<4>fun checkOrder(menu: ArrayList<Menu>,total: Array<Int>,flags:Boolean):Boolean

fun checkOrder(menu: ArrayList<Menu>,total: Array<Int>,flags:Boolean):Boolean{

    //주문이 하나도 없으면 종료
    var flag=false
    for(i in menu){
        if(i.flag) flag=true
    }
    if(!flag){
        println("아직 담은 메뉴가 없습니다.\n")
        return flag
    }

    println("\n[Order]")
    var idx=1
    for(i in menu.indices){
        if(menu[i].flag) print("${idx++}.")
        menu[i].orderList()
    }
    if(flags){
        println("0.뒤로가기\n-1.전체 삭제")
    }


    println("\n[Total]\n${total[0]} 원")

    return flag
}

-담아둔 주문 목록을 보여주는 함수

-주문 정보 확인 및 수정하거나 결제시 실행된다.

 

<5>fun main()

fun main(){
    val menu=ArrayList<Menu>()
    init(menu)

    var money:Int?
    val total= arrayOf<Int>(0)


    //결제시 주문 대기수 올라감
    var waiting=0



    while (true){
        println("현재 소지한 금액을 입력해주십시오")
        try {
            money= readLine()?.toString()?.toInt()
            if(money==null||money<0){
                println("다시 입력해주세요")
                continue
            }
        }catch (e:Exception){
            println("다시 입력해주세요")
            continue
        }
        break
    }

    //주문 대기수
    //결제시 주문대기자 수 증가
    var endFlag=true
    val wait=thread(start=true){
        try {
            Thread.sleep(5000)
        }catch (e:Exception){
        }

        while (endFlag){
            try {
                println("현재 주문 대기수:${waiting}")
                Thread.sleep(5000)
            }catch (e:Exception){
            }
        }
        println("종료되었습니다")
    }

    while (true){

        println("\n로딩중...")
        try {
            Thread.sleep(3000)
        }catch (e:Exception){}

        println()

        var category:Int?
        try {
            println("\n[MENU]\n")
            println("1.피자\n2.음료\n3.사이드\n4.주문확인 및 수정\n5.결제\n0.종료")
            category= readLine()?.toString()?.toInt()
            if(category!=null&&category==0) break

            if(category==null||(category!=0&&category !in 1..5)) {
                println("다시 입력해주세요")
                continue
            }

        }catch (e: Exception){
            println("다시 입력해주세요")
            continue
        }

        if(category==5){
            if(total[0]==0){
                println("아직 주문하지 않았습니다. 메뉴를 담은 후에 결제해주세요")
            }else{
                checkOrder(menu,total,false)
                println("결제하시겠습니까?\n1.Yes    2.No")
                var choose:Int?
                while (true){
                    try {
                        choose= readLine()?.toString()?.toInt()
                        if(choose==null||choose !in 1..2){
                            println("다시 입력해주세요")
                            continue
                        }
                    }catch (e: Exception){
                        println("다시 입력해주세요")
                        continue
                    }
                    break

                }
                if(choose==1){
                    val time=LocalDateTime.now()
                    val form=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                    val formtime=DateTimeFormatter.ofPattern("HHmm")
                    val curtime=time.format(formtime).toInt()

                    if(curtime in 2000..2100){
                        println("현재시간은 ${curtime/100}시 ${curtime%100}분입니다.")
                        println("은행 점검 시간은 20시 00분 ~ 21시:00이므로 결제할 수 없습니다.")
                        continue
                    }


                    if(money!!<total[0]){
                        println("현재 잔액은 ${money}원으로 ${total[0]-money}원이 부족합니다")
                        continue
                    }
                    money = money!!.minus(total[0])
                    total[0]=0
                    menu.clear()
                    init(menu)


                    println("결제가 완료되었습니다(${time.format(form)})")
                    println("남은 금액: ${money}원")
                    ++waiting
                }else{
                    println("결제가 취소되었습니다")
                }


            }

        }else{
            orderMenu(menu,category,total)
        }

    }

    endFlag=false

}

-wait쓰레드로 주문대기수 지속적으로 출력:endFlag를 이용해 종료시 같이 종료되도록 함.

-while문을 이용해 특정 작업종료이후에도 메인메뉴를 보여주는것을 반복시키도록 함

-위의 while문 내에 Thread.sleep()을 이용해 특정작업종료 후 대기시간이 있도록 만들음

-메인 메뉴에 피자, 음료,사이드,주문 확인 및 수정, 결제, 종료를 넣고 선택이 그에 맞는 함수를 실행.

-결제의 경우 메인메뉴의 while문에서 처리

-LocalDateTime을 이용해 결제시 주문이 안되는 시간을 설정해 놓고 결제완료시 해당 시간을 출력하도록 함

 

 

3. 느낀점

-입력받는 값에 대한 예외처리가 번거로웠던 느낌이다. 다음부터는 입력 받는것에 대해 함수를 짜서 해봐야겠다