[TIL] 키오스크 팀 프로젝트 초안 코드 살펴보기

남보경·2023년 7월 25일
1

TIL

목록 보기
3/10
post-thumbnail

내일배움캠프 이번 주차 과제는 키오스크 기능 만들기였다.
팀원들과 같이 해야해서 다같이 전체적인 부분은 잘 짠 사람 것으로 채택하고 나머지 상세 부분을 따로 작성해오기로 했다.

작성하면서 생각보다 파일이 많아지고 더 복잡해지다보니 머릿속에서 논리가 엉키는 느낌이라 좀 정리하고 개선할 부분은 없는지 찾아보고자 한다.

일단 전체적인 코드 구조는 인스턴스를 한 클래스에 몰아놓아서 해당 클래스로 모든 클래스에 접근할 수 있게 추상화를 해봤다.

또한, 숫자를 console창에 입력하는 것으로 각기 다른 화면과 기능들을 불러와야 했기 때문에 그리고 튜터님이 이전 프로젝트 때 예시로 보여준 enum 활용법이 너무 흥미로워서 enum을 활용해봤다.

instances.swift

import Foundation

class Instances {
    let main = Main()
    let printing = PrintMenu()
    let operating = Operator()
    let toHome = Home()
    let selecting = Select()
    let picking = Pick()
    let cart = Cart()
    let checkout = Checkout()
    let administration = Admin()
    let exit = Exit()
    let pns = PikklesAndSauces()
}

Operator.swift

import Foundation

enum Set{
    // 기본 화면 및 기능
    case home, pick, cart, checkout, admin, exit, clearCart
    
    // 카테고리
    case pikklesAndSauces, pizza, pasta, drink, side
    
    // 피클 & 소스 메뉴
    case pikkleM, pikkleL, garlicDip, hotSauce
}

class Operator {
    func oper(_ input: Set) {
        
        switch input {
        // 기본 메뉴
        case .pick : instances.picking.pick()
        case .cart : instances.cart.cart()
        case .checkout : instances.checkout.checkout()
        case .admin : instances.administration.admin()
        case .home: instances.toHome.home()
        case .clearCart : instances.cart.cartContent = [:]
        case .exit : instances.exit.exit()
            
        // 카테고리
        case .pikklesAndSauces : instances.pns.pns()

        default : instances.toHome.home()
        }
    }
}

우리는 도미노피자 키오스크를 만들어보자고 정했다. 홈 화면에서는 처음하려는 액션을 고를 수 있게 되어있고, 두 번째 레이어(?)에는 메뉴별 카테고리, 세 번째 레이어에서는 상세 상품을 고를 수 있게 설계했다.

상세 상품을 고르면 몇 개를 구매할지 물어보고 그 숫자를 받아서 장바구니에 추가하는 방식으로 그려봤다.

조금 공을 들였던 부분은 메뉴를 프린팅 하는 부분, 번호를 입력하고 받는 과정과 옵셔널에 대한 에러처리 부분, 입력값에 따른 조건문을 모은 부분들을 참조하는 방식으로 짜는 과정이었다.

Home.swift

class Home{
    let menus: [String] = [
        "1. 주문하기",
        "2. 장바구니",
        "3. 결제하기",
        "4. 관리자 메뉴",
        "0. 종료"
    ]
    
    let numset: [Int: Set] = [
        1 : .pick,
        2 : .cart,
        3 : .checkout,
        4 : .admin,
        0 : .exit
    ]
    
    func home() {
        print("[ WELCOME TO DOMINO PIZZA ]")
        instances.printing.printMenu(menus) // 메뉴 프린팅
        var numChoice: Int = instances.selecting.numSelect() // Int 반환
        var numToSet: Set = numset[numChoice]!
        
        while true {
            if 0 <= numChoice && numChoice <= 4 {
                // 범위 내 숫자일 경우 Set type 변수에 할당하고 break
                numToSet = numset[numChoice]! 
                // numSelect 에서 Int 아닌 경우 오류처리 했으므로 강제 언래핑
                break
            }
            else {
                print("메뉴에 없는 숫자 입니다.")
                print("올바른 숫자를 다시 입력해주세요.")
                numChoice = instances.selecting.numSelect()
            }
        }
        
        instances.operating.oper(numToSet)
        
    }
}

홈 화면 하나만 프린트할 것이 많았다면 그냥 냅뒀겠지만 모든 화면마다 출력하고 입력받아야 하는 값들이 존재해서 그냥 배열을 줬을 때 프린트 해버리는 기능을 만들었다. 매번 쓰는 것 보다는 편하긴 하겠지만... 좀 더 팀원들이 관리자 기능으로 메뉴나 가격을 변경하고 싶어하던 것을 생각해 보면 그 기능을 구현하기 위해 따로 클래스를 만들고 배열을 모아서 관리가능하면서도 불러오기 편하게, 코드가 간결해지도록 바꿔보고 싶다.

지금은 옵셔널 처리가 select 과정에서 한 번, 화면에서 입력받을 때 또 한 번 진행되는데 이 부분도 두 번이나 매 화면마다 거치게 되는 것이 좀 아니꼽다...?
옵셔널도 분리를 해버리고 팀원들의 파일도 받다보면 좀 너무 파일이 많아지려나 싶기도 하고... 하지만 코드가 그만큼 간결해지면 또 가치 있는 것 같다...

Select.swift

class Select{
    func numSelect() -> Int{
        print("")
        print("원하시는 메뉴를 숫자로 입력해주세요")
        var n: Int = Int(readLine()!) ?? 404
        
        // 에러코드가 뜨지 않는 경우 함수 종료되며 n값 리턴
        if n != 404 {
            return n
        }
        
        // 에러코드가 뜨는 경우 맞는 값이 입력될 때 까지 반복
        while n == 404 {
            print("잘못된 값이 입력 됐습니다")
            print("숫자만 다시 입력 해주세요")
            n = Int(readLine()!) ?? 404
        }
        return n
    }
}

select 과정에서 옵셔널 값에 대한 처리가 좀 더 분명히 됐으면 좋겠다는 생각이 들었다.
Home 화면에서 입력 시에는 오류들이 없지만 좀 더 깊은 레이어로 파고들기 시작하니 자꾸 numSelect() 부분에서 fatal 에러가 발생했다. 이 에러만 어떻게 넘어가게 처리하는 것이 아니라 옵셔널 값을 처리하는 부분에 대해서 철저한 분석과 보정이 필요한 것 같다. 내일은 이부분을 팀원들과 의견을 나누면서 고쳐보려고 한다.

PrintMenu.swift

class PrintMenu {
    func printMenu(_ menus: [String]) {
        for menu in menus {
            print(menu)
        }   
    }
}

처음에는 이 for ~ in ~ 이 구문이 너무 낯설고 왜 선언되지도 않은 단어가 갑자기 튀어나오는지 이해도 되지 않았다. 그런데 직접 사용해보고 나니 넘나 꿀인것을...
while과는 비교도 되지 않을 정도로 간결하게 코드가 끝나버린다.

PickklesAndSauces.swift

class PikklesAndSauces {
    
    var menuName: [String]  = [
        "우리피클 M",
        "우리피클 L",
        "갈릭디핑소스",
        "핫소스",
    ]
    
    var menuCost: [Int]  = [
        500,
        800,
        200,
        100,
    ]
    
    func pns() {
        var menus: [String] = [
            "1. \(menuName[0])      | 가격: \(menuCost[0])",
            "2. \(menuName[1])      | 가격: \(menuCost[1])",
            "3. \(menuName[2])      | 가격: \(menuCost[2])",
            "4. \(menuName[3])      | 가격: \(menuCost[3])",
            "5. 홈으로 돌아가기",
            "0. 종료"
        ]

        let numset: [Int: Set]  = [
            1 : .pikkleM,
            2 : .pikkleL,
            3 : .garlicDip,
            4 : .hotSauce,
            5 : .home,
            0 : .exit,
        ]
        
        instances.printing.printMenu(menus) // 메뉴 프린팅
        var numChoice: Int = instances.selecting.numSelect() // Input Int 반환
        var numToSet: Set = numset[numChoice]! // Int를 Set값으로 변환
        
        while true {
            if 0 <= numChoice && numChoice <= 5 {
                // 범위 내 숫자일 경우 Set type 변수인 numToSet에 할당하고 break
                numToSet = numset[numChoice]!
                // numSelect 에서 Int 아닌 경우 오류처리 했으므로 강제 언래핑
                break
            }
            else {
                // 범위 내 숫자 외의 경우에는 반복문에 갇힘
                print("메뉴에 없는 숫자 입니다.")
                print("올바른 숫자를 다시 입력해주세요.")
                numChoice = instances.selecting.numSelect()
            }
        }
        
        let cartAddName = menuName[numChoice - 1]
        print("\(cartAddName)를 몇 개 구매하시겠습니까?")
        print("(숫자만 입력 | 예시. 3개 -> 3)")
        
        let cartAddCount: Int = Int(readLine()!) ?? 404
        if cartAddCount != 404 {
            let cartAddContent: [String : Int] = [cartAddName : cartAddCount]
            instances.cart.cart(cartAddContent)
        }
    }
}

가장 많은 시간이 빨린 부분이다.
한 화면에서 생각보다 너무 많은 일들이 일어난다. 코드도 많이 길어지게 되니 조금 생각이 많아진다.

관리 및 수정이 편하도록 배열을 관리하고, 옵셔널 처리도 단순화 시키면서 참조하는 것처럼 다시 짜보고 싶다. 반복문도 계속 반복되는 부분이라 추출해서 메소드를 참조하는 것처럼 진행해야 하나 싶다.

그리고 줄바꿈 기능이나 화면이 넘어갈 때마다 console을 clear하고 작성할 수 있게도 하고 싶은데 시간이 부족해서 찾아보지 못했다. 내일은 이부분도 찾아봐서 좀 더 깔끔하게 출력이 나올 수 있게 해보고 싶다.

개선 필요한 부분 정리
1. 옵셔널 처리에 대해 어딘가에서 nil이 발생하는데 이 부분이 왜 발생하는지 확인하고 고치면서 옵셔널 처리를 단순화해서 클래스로 분리하기
2. 관리자 기능에서 메뉴가 수정가능하도록 기능을 구현하면서 배열 혹은 다른 컬렉션 형태를 이용해서라도 좀 더 코드가 간결해지고 수정하기 용이하도록 변경하기
3. console clear 기능 찾아보기
4. 줄바꿈 찾아보기
5. 가능하다면 기능의 갯수를 줄여서 최대한 파일이 너무 많아지지 않게 관리

profile
꿈꾸자 그리고 그것을 이뤄내자

0개의 댓글