키오스크 중복되는 관리하기 v6.01

김성수·2023년 6월 1일
0

키오스크

목록 보기
3/4

들어가면서

새로운 기능을 추가하는 것보다는 코드를 리팩토링하는 것에 집중하고 있다.
내가 짠 코드는 어떤 문제점이 있을까
무지무지 많지만 어디서부터 건들여야할지 참 어렵다.
오늘은 상품(Product) 객체에서 중복되는 코드를 ProductService 클래스에 메서드화 시켜서
유지보수를 향상시킨 경험을 기록한다.



중복되는 코드를 한 곳에서 관리하자!

Main 메뉴는 나름 컨트롤러 역할을 할 수 있도록 노력했다.

핵심 비즈니스 로직은 컨트롤러에서 직접 구현되지 않도록 신경썼다.

처음에 버거, 디저트, 음료 .. 등등을 하나의 도메인이라고 생각하고 객체로 만들어줬었다.

그런데 생각해보면 메뉴가 굉장히 많아진다면 너무 많은 Product 객체가 생겨서 관리하기 어려워질 수 있을지도 모른다는 생각이 들었다.

맥주, 버거, 치킨, 디저트, 음료 이렇게 다섯개의 상품 객체가 존재하는데

메뉴가 100개라면 클래스가 100개가 있어야 한다.

DB를 사용했다면 Product 도메인, 컨트롤러, 리포지토리, 서비스 레이어를 각각 구현하면 되었겠지만

자바로만 구현하다보니 데이터를 저장할 실질적인 객체가 필요한 실정이다.


Product 객체 안에서 모든 상품들을 초기화 시켜줄 수도 있을 것이다.

하지만 그렇게 만들게 되면 MainMenu 클래스(컨트롤러)에서 각각의 상품을 호출할 때마다

각각의 상품 객체를 호출해줘야 하므로 현재 설계 구조가 더 효율적이라고 판단했다.

(사실 더 좋은 방법이 있을지도 모른다. 아니, 분명 존재할 것이다.)



무엇이 중복되는가?

각각의 상품 객체에 들어가보면 choiceProduct 메서드와, detailMenu 메서드에서 중복되는 코드가 발생한다.

만약 detailMenu 메서드에서 화면에 출력하는 로직이 변경된다면 모든 Product 객체 로직을 변경해줘야 하는 번거로움이 있다.


public void detailMenu(){
        bearArr = new ArrayList<>();
        bearArr.add(new ProductMenu("생맥주", 4.0, "거품이 일품인 생맥주!"));
        bearArr.add(new ProductMenu("병맥주", 4.0, "마시면 머리까지 시원해지는 병맥주!"));

        System.out.println("[ Bears MENU ]");
    }
        for(int i = 0; i < object.size(); i++){
            System.out.println((i+1) + " " + String.format("%-15s", object.get(i).name)+ " | Won "
                    + object.get(i).price + " | " + object.get(i).description);
        }

예를 들어 화면에 상품 이름을

햄버거                  |
치즈버거               |
모짜렐라 인 더 버거 |

위와 같이 출력해줘야 한다면 String.format() 메서드를 사용해야할 것이다.

(참고로 한글은 전각 문자로써 2byte이기 때문에 문자열을 반각 문자로 변경해준 다음 사용해야 한다. 구글링하면 전각문자 -> 반각문자로 만들어주는 메서드가 있는데, 이해가 잘 안되어서 적용하지는 않았다.)

그런데 모든 Product 객체에 String.format()을 적용해준다고 생각해보자. 엄청나게 귀찮다.

심지어 Product 객체가 백개라면? 어우.. 상상도 하기 싫지 않은가?

그래서 ProductService에서 공통적으로 등장하는 로직을 메서드로 정리하였다.

이로써 ProductService 메서드 로직만 변경해주면 모든 Product 객체가 변경된다.

package main.product;

import java.util.ArrayList;

/**
 * Product 객체 내부 공통 로직
 */
public class ProductService {

    public ProductService(){

    }

    // 상품 메뉴 보여주기
    public static void detailMenuPrint(ArrayList<ProductMenu> object){

        System.out.println("아래 상품 메뉴판을 보시고 상품을 골라 입력해주세요.");

        for(int i = 0; i < object.size(); i++){
            System.out.println((i+1) + " " + String.format("%-15s", object.get(i).name)+ " | Won "
                    + object.get(i).price + " | " + object.get(i).description);
        }
    }

    // 상품 메뉴를 선택했을 시
    public static ProductMenu choiceProductPrint(ArrayList<ProductMenu> object, int choiceDetailMenu){

        // 장바구니에 상품 메뉴를 추가함.
        System.out.println("\"" + object.get(choiceDetailMenu-1).name + " | Won " + object.get(choiceDetailMenu-1).price + " | "
                + object.get(choiceDetailMenu-1).description + "\"");
        System.out.println();
        System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
        System.out.println();
        System.out.println("1. 확인         2. 취소");

        // 상품 메뉴를 주문 리스트에 담기 위해 해당 상품을 반환하고, 반환된 값을 장바구니 객체에 담는다.
        return object.get(choiceDetailMenu-1);
    }
}



남발되던 주석을 제거하다.

주석이 너무 과하다 보니 가독성을 해친다는 느낌을 받았다. 그래서 올바른 주석 표기법을 알아봤는데,

보통 public function 단위로 주석 기록한다는 것을 알게되어서 불필요한 주석은 모두 지워버렸다.

이전 코드

 public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        // 메뉴를 값을 저장해놓음으로써 동적으로 메뉴를 확장하거나 축소할 수 있다.
        Map<Integer, Product> menuMap = new HashMap<>();
        menuMap.put(1, new Product(new Buger()));
        menuMap.put(2, new Product(new Dessert()));
        menuMap.put(3, new Product(new Drinks()));
        menuMap.put(4, new Product(new Chicken()));
        menuMap.put(5, new Product(new Bear()));

        // 가게 명 설정
        // 메인 메뉴에 출력될 이름 설정 ex ) "name에 오신걸 환영합니다."
        String menuName = "롯데리아";

        // 상세 상품 선택
        int choiceDetailMenu = 0;

        // 상세 상품 장바구니에 담기 위해 선언
        ProductMenu choiceProduct = new ProductMenu();

        //장바구나 획인 or 취소
        int orderOrCancel = 0;

        // 주문 상품을 담을 장바구니 역할인 orderList 인스턴스화
        OrderList orderList = new OrderList();

        // 주문 횟수로 어떤 상품이 장바구니에 담기는지 파악
        int addProductCnt = 0;

        // 총 Order 수(대기번호수)
        int totalOrderCnt = 0;

        while (true) {
            // 메인 메뉴리스트를 출력합니다.
            // 메인 메뉴가 변경될 때마다 MainMenu 클래스를 변경하지 않도록 클래스를 분리하여 결합도를 낮춥니다.
            MainMenuList mainMenuList = new MainMenuList();
            mainMenuList.mainMenuList(menuName);

            // 메인 메뉴판 선택 버거, 디저트, 음료, 치킨 중...
            int choiceMenu = in.nextInt();

            // 화면 전환 효과를 위해 공백을 입력합니다.
            clearScreen();

            // 상세 메뉴를 추상화한 Product
            // Product 객체를 통해 객체를 갈아끼워주기만 하면 됨.
            Product product = menuMap.get(choiceMenu);

이후 코드


    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        // 메뉴를 값을 저장해놓음으로써 동적으로 메뉴를 확장하거나 축소할 수 있다.
        Map<Integer, Product> menuMap = new HashMap<>();
        menuMap.put(1, new Product(new Buger()));
        menuMap.put(2, new Product(new Dessert()));
        menuMap.put(3, new Product(new Drinks()));
        menuMap.put(4, new Product(new Chicken()));
        menuMap.put(5, new Product(new Bear()));

        ProductMenu choiceProduct = new ProductMenu();

        OrderList orderList = new OrderList();

        int choiceDetailMenu = 0;

        int orderOrCancel = 0;

        int addProductCnt = 0;

        int totalOrderCnt = 0;

        while (true) {
            MainMenuList mainMenuList = new MainMenuList();
            // 메인 화면
            mainMenuList.mainMenuList();

            int choiceMenu = in.nextInt();

            clearScreen();

            Product product = menuMap.get(choiceMenu);



알게된 점

String.format() 사용하기
오늘 4조에서 코드리뷰를 하는 시간을 가졌는데 어느분이 String.format을 이용하여 출력을
정렬하셨어서 그 팁을 내 코드에 적용해봤다.


중복되는 코드가 3번 이상이라면 내 코드에 의심을 해봐야 한다.

호돌맨님께서 하신 말씀인데, 프로젝트를 만들면서 최대한 적용해보려고 노력하고 있다.

profile
깊이 있는 소프트웨어 개발자가 되고 싶습니다.

0개의 댓글