본문 바로가기
개발자 꿈나무의 하루/01_Boot Camp

(네이버클라우드 부트캠프) 15일차 - 실습프로젝트(클래스)

by kk_naks 2024. 6. 14.

1. 회원 서브메뉴 메서드

  1.1 서브메뉴 분기 

- 서브메뉴가 삽입될 자리는 
- 모든 조건이 참일 경우(올바른 입력)
   - 메인메소드 
    | - 프로세스 메소드
         | - 서브메뉴 
    static void processMenu(String menuTitle, String[] menus) {
        printSubMenu(menuTitle, menus);
        while (true) {
            String command = prompt("메인/" + menuTitle);
            if (command.equals("menu")) {
                printSubMenu(menuTitle, menus);
                continue;
            } else if (command.equals("9")) { // 이전 메뉴 선택
                break;
            }

            try {
                int menuNo = Integer.parseInt(command);
                String subMenuTitle = getMenuTitle(menuNo, menus);
                if (subMenuTitle == null) {
                    System.out.println("유효한 메뉴 번호가 아닙니다.");
                } else {
                    
                    //메뉴별 서브메뉴 분기점//
                                        
                }
            } catch (NumberFormatException ex) {
                System.out.println("숫자로 메뉴 번호를 입력하세요.");
            }
        }
    }
- 각 서브메뉴가 분기하는 코드는 switch문법을 사용한다.
// 다음과 같이 분기를 한다.
switch (menuTitle) {
    case "회원":
      //회원 메뉴 메서드 실행
      break;
    case "팀":
      //메뉴 메서드 실행
      break;
    case "프로젝트":
      //프로젝트 메뉴 메서드 실행
      break;
    case "게시판":
      //게시판 메뉴 메서드 실행
      break;
  }

 

  1.2 회원 서브메뉴 

- 회원 서브메뉴 : 등록/목록/조회/변경/제거/이전
  |- 등록 : 이름,이메일,패스워드,연락처 입력
  |- 목록 : 전체 회원번호/이름/이메일 출력
  |- 조회 : (회원번호 유효입력 시) 회원에 대한 이름, 이메일, 연락처 출력
  |- 변경 : (회원번호 유효입력 시) 회원에 대한 이름, 이메일, 연락처 변경
  |- 제거 : (회원번호 유효입력 시) 회원번호 삭제 및 회원목록 재정렬
- 기본구조는 switch문법을 사용하여 구성한다. 
switch (메뉴명) {
  case "등록":
    // 등록 수행 메서드
    break;
  case "목록":
    // 등록 수행 메서드
    break;
  case "조회":
    // 등록 수행 메서드
    break;
  case "변경":
    // 등록 수행 메서드
    break;
  case "제거":
    // 등록 수행 메서드
    break;
}

//이전 메뉴는 processMenu() 메서드에서
//command.equals("9")에서 상위메서드로 회귀 한다.

  

  - 클래스 작성

- 각 메서드의 정보를 담을 클래스가 필요하다.
- 유저 클래스 정의 
 - 이름, 이메일, 비밀번호, 연락처 
pulic class user{
	String name;
    String email;
    String password;
    String tel;
}

//전역 변수로 
static final int MAX_SIZE = 100;
static User[] users = new User[MAX_SIZE];

 

  - 등록메서드 작성

- User class를 사용하여 user를 인스턴스 한다. 
- user의 멤버변수에 접근하기 위해 user.(멤버변수명)으로 데이터를 대입한다. 
- 이후 위에서 User[]로 선언된 배열에 userLength를 사용하여 생성된 user의 레퍼런스를 넘긴다.
- 메서드가 종료되면서 new로 생성된 user의 레퍼런스는 garbage가 된다.
//등록 메서드
 static void addUser() {
    User user = new User();
    user.name = prompt.input("이름?");
    user.email = prompt.input("이메일?");
    user.password = prompt.input("암호?");
    user.tel = prompt.input("연락처?");
    users[userLength++] = user;
  }

 

  - 목록메서드 작성

- for문을 생성하여 등록된 유저수(userLength) 만큼 반복한다.
- user를 새로 인스턴스 하여 users의 i번째 유전 정보가 담긴 레퍼런스를 받는다.
- 레퍼런스를 참조하여 유저 정보를 출력한다.
// 목록 메서드
  static void listUser() {
    System.out.println("번호 이름 이메일");
    for (int i = 0; i < userLength; i++) {
      User user = users[i];
      System.out.printf("%d %s %s\n", i + 1, user.name, user.email);
    }
  }

 

  - 조회메서드 작성

- prompt를 사용하여 유효 번호 판별을 실행한다. 
- 유효하지 않은 데이터가 들어오면 return을 통해 메서드를 종료한다.
- User타입의 user를 인스턴스하여 회원번호를 통한 유저 정보 레퍼런스를 받는다.

 

// 조회 메서드
  static void viewUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    System.out.printf("이름 : %s\n", user.name);
    System.out.printf("이메일 : %s\n", user.email);
    System.out.printf("연락처 : %s\n", user.tel);
  }

 

  - 변경메서드 작성

- 유효성 검증 후 해당 번호의 유저 정보를 user에 인스턴스한다.
- 이후 재할당을 한다. 
// 변경 메서드
  static void updateUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    user.name = prompt.input(String.format("이름(%s):", user.name));
    user.email = prompt.input(String.format("이메일(%s):", user.email));
    user.password = prompt.input(String.format("비밀번호(%s):", user.password));
    user.tel = prompt.input(String.format("연락처(%s):", user.tel));
    System.out.println("변경했습니다.");
  }

 

  - 삭제메서드 작성

- 유효성 검증을 해당 번호의 유저번호를 받는다. 
- for문을 통해 users의 배열에서 레퍼런스 값들을 조정한다. 
- 마지막 레퍼런스 주소를 null로 하여 garbage로 만든다.
// 제거 메서드
  static void deleteUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    for (int i = userNo; i < userLength; i++) {
      users[i - 1] = users[i];
    }
    userLength--;
    users[userLength] = null;
    System.out.println("삭제했습니다.");
  }

 

  1.3 회원 서브메뉴 완성 코드 

try {
        int menuNo = Integer.parseInt(command);
        String subMenuTitle = getMenuTitle(menuNo, menus);
        if (subMenuTitle == null) {
          System.out.println("유효한 메뉴 번호가 아닙니다.");
        } else {
          switch (menuTitle) {
            case "회원":
              //회원 메뉴 처리 메서드로 이동
              executeUserCommand(subMenuTitle);
              break;
            case "팀":
              executeTeamCommand(subMenuTitle);
              break;
            case "프로젝트":
              executeProjectCommand(subMenuTitle);
              break;
            case "게시판":
              executeBoardCommand(subMenuTitle);
              break;
            default:
              System.out.printf("%s 메뉴의 명령을 처리할 수 없습니다.\n", menuTitle);
          }
        }
      } catch (NumberFormatException ex) {
        System.out.println("숫자로 메뉴 번호를 입력하세요.");
      }
static void excuteUserCommand(String command) {
    System.out.printf("[%s]\n", command);
    switch (command) {
      case "등록":
        addUser();
        break;
      case "목록":
        listUser();
        break;
      case "조회":
        viewUser();
        break;
      case "변경":
        updateUser();
        break;
      case "삭제":
        deleteUser();
        break;
    }
  }
static void addUser() {
    User user = new User();
    user.name = prompt.input("이름?");
    user.email = prompt.input("이메일?");
    user.password = prompt.input("암호?");
    user.tel = prompt.input("연락처?");
    users[userLength++] = user;
  }

  static void listUser() {
    System.out.println("번호 이름 이메일");
    for (int i = 0; i < userLength; i++) {
      User user = users[i];
      System.out.printf("%d %s %s\n", i + 1, user.name, user.email);
    }
  }

  static void viewUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    System.out.printf("이름 : %s\n", user.name);
    System.out.printf("이메일 : %s\n", user.email);
    System.out.printf("연락처 : %s\n", user.tel);
  }

  static void updateUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    user.name = prompt.input(String.format("이름(%s):", user.name));
    user.email = prompt.input(String.format("이메일(%s):", user.email));
    user.password = prompt.input(String.format("비밀번호(%s):", user.password));
    user.tel = prompt.input(String.format("연락처(%s):", user.tel));
    System.out.println("변경했습니다.");
  }

  static void deleteUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    for (int i = userNo; i < userLength; i++) {
      users[i - 1] = users[i];
    }
    userLength--;
    users[userLength] = null;
    System.out.println("삭제했습니다.");
  }

 

2. 클래스 파일로 나누기

- 클래스 파일에 여러 기능이 포함되면, 유지보수성이 나빠진다. 
- 기능별 클래스 파일을 나누어 기능별 메서드/ 사용자 정의 데이터 타입으로 클래스 파일을 나눈다.
- 클래스를 나눌때 상호 연관(Association)이 되면 추후 유지 보수성이 불리하다.
- 한쪽만 import 하게 클래스 파일을 만들어야 한다. 
- 클래스파일은 호출 될때 JVM에 올라간다. 

 

  2.1 데이터타입별 분리 

- 회원 클래스는 사용자 정의 데이터 타입으로 별도 클래스로 관리 하여야한다. 
package bitcamp.myapp2;

public class User {

  String name;
  String email;
  String password;
  String tel;
}

  2.2 기능별 분리 

  - 회원관련 메뉴 분리

- 회원 탭에 포함된 기능(등록/목록/조회/변경/제거)를 별도의 클래스 파일로 분리 
- 사용된 배열과 정수들도 같이 이사해야한다. (상호 연관을 낮추기 위해)
package bitcamp.myapp2;

public class UserCommand {
  static final int MAX_SIZE = 10;
  static User[] users = new User[MAX_SIZE];
  static int userLength = 0;

  static void excuteUserCommand(String command) {
    System.out.printf("[%s]\n", command);
    switch (command) {
      case "등록":
        addUser();
        break;
      case "목록":
        listUser();
        break;
      case "조회":
        viewUser();
        break;
      case "변경":
        updateUser();
        break;
      case "삭제":
        deleteUser();
        break;
    }
  }

  static void addUser() {
    User user = new User();
    user.name = prompt.input("이름?");
    user.email = prompt.input("이메일?");
    user.password = prompt.input("암호?");
    user.tel = prompt.input("연락처?");
    users[userLength++] = user;
  }

  static void listUser() {
    System.out.println("번호 이름 이메일");
    for (int i = 0; i < userLength; i++) {
      User user = users[i];
      System.out.printf("%d %s %s\n", i + 1, user.name, user.email);
    }
  }

  static void viewUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    System.out.printf("이름 : %s\n", user.name);
    System.out.printf("이메일 : %s\n", user.email);
    System.out.printf("연락처 : %s\n", user.tel);
  }

  static void updateUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    user.name = prompt.input(String.format("이름(%s):", user.name));
    user.email = prompt.input(String.format("이메일(%s):", user.email));
    user.password = prompt.input(String.format("비밀번호(%s):", user.password));
    user.tel = prompt.input(String.format("연락처(%s):", user.tel));
    System.out.println("변경했습니다.");
  }

  static void deleteUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    for (int i = userNo; i < userLength; i++) {
      users[i - 1] = users[i];
    }
    userLength--;
    users[userLength] = null;
    System.out.println("삭제했습니다.");
  }
}

 

  - 입력 메서드 분리 

- 입력 메서드는 다양한 클래스에서 사용하므로 분리
package bitcamp.myapp2;

public class prompt {
  static String input(String title) {
    System.out.print(title);
    return App.keyboardScanner.nextLine();
  }
}

 

3. 완성된 코드

  3.1 메인코드 

package bitcamp.myapp2;

public class App {
  static java.util.Scanner keyboardScanner = new java.util.Scanner(System.in);
  static String[] mainMenus = new String[] {"회원", "팀", "프로젝트", "게시판", "도움말", "종료"};
  static String[][] subMenus =
      new String[][] {{"등록", "목록", "조회", "변경", "삭제"}, {"등록", "목록", "조회", "변경", "삭제"},
          {"등록", "목록", "조회", "변경", "삭제"}, {"등록", "목록", "조회", "변경", "삭제"}};

  public static void main(String[] args) {
    String command;
    printMainMenu();
    while (true) {
      try {
        command = prompt.input("메인> ");
        if (command.equals("menu")) {
          printMainMenu();
          continue;
        }
        int menuNo = Integer.parseInt(command);
        String menuTitle = getMenuTitle(menuNo, mainMenus);
        if (menuTitle == null) {
          System.out.println("유효한 메뉴 번호가 아닙니다.");
        } else if (menuTitle.equals("종료")) {
          break;
        } else {
          if (menuNo >= 1 && menuNo <= 4) {
            processSubMenu(menuTitle, subMenus[menuNo - 1]);
          } else {
            System.out.println(mainMenus[menuNo - 1]);
          }
        }
      } catch (NumberFormatException ex) {
        System.out.println("숫자로 메뉴 번호를 입력하세요.");
      }
    }
    System.out.println("종료합니다.");
    keyboardScanner.close();
  }

  static void printMainMenu() {
    String boldAnsi = "\033[1m";
    String redAnsi = "\033[31m";
    String resetAnsi = "\033[0m";
    String appTitle = "[팀 프로젝트 관리 시스템]";
    String line = "----------------------------------";
    System.out.println(boldAnsi + line + resetAnsi);
    System.out.println(boldAnsi + appTitle + resetAnsi);
    for (int i = 0; i < mainMenus.length; i++) {
      if (mainMenus[i].equals("종료")) {
        System.out.printf("%s%d. %s%s\n", (boldAnsi + redAnsi), (i + 1), mainMenus[i], resetAnsi);
      } else {
        System.out.printf("%d. %s\n", (i + 1), mainMenus[i]);
      }
    }
    System.out.println(boldAnsi + line + resetAnsi);
  }

  static void printSubMenu(String menuTitle, String[] menus) {
    System.out.printf("[%s]\n", menuTitle);
    for (int i = 0; i < menus.length; i++) {
      System.out.printf("%d. %s\n", i + 1, menus[i]);
    }
    System.out.println("9. 이전");
  }

  static boolean isValidateMenu(int menuNo, String[] menus) {
    return menuNo >= 1 && menuNo <= menus.length;
  }

  static String getMenuTitle(int menuNo, String[] menus) {
    return isValidateMenu(menuNo, menus) ? menus[menuNo - 1] : null;
  }

  static void processSubMenu(String menuTitle, String[] menus) {
    printSubMenu(menuTitle, menus);
    while (true) {
      String command = prompt.input(String.format("메인/%s> ", menuTitle));
      if (command.equals("menu")) {
        printSubMenu(menuTitle, menus);
        continue;
      } else if (command.equals("9")) {
        break;
      }
      try {
        int subMenuNo = Integer.parseInt(command);
        String subMenuTitle = getMenuTitle(subMenuNo, menus);
        if (subMenuTitle == null) {
          System.out.println("유효한 메뉴 번호가 아닙니다.");
        } else {
          switch (menuTitle) {
            case "회원":
              UserCommand.excuteUserCommand(subMenuTitle);
              break;
            case "팀":
              excuteTeamCommand(subMenuTitle);
              break;
            case "프로젝트":
              excuteProjectCommand(subMenuTitle);
              break;
            case "게시판":
              excuteBoardCommand(subMenuTitle);
              break;
          }
        }
      } catch (NumberFormatException ex) {
        System.out.println("숫자로 메뉴 번호를 입력하세요.");
      }
    }
  }


  static void excuteTeamCommand(String command) {
  }

  static void excuteProjectCommand(String command) {
  }

  static void excuteBoardCommand(String command) {
  }


}

 

  3.2 클래스 코드

package bitcamp.myapp2;

public class User {

  String name;
  String email;
  String password;
  String tel;
}

  3.3 프롬프트 코드

package bitcamp.myapp2;

public class prompt {
  static String input(String title) {
    System.out.print(title);
    return App.keyboardScanner.nextLine();
  }
}

  3.4 유저커맨드 코드

package bitcamp.myapp2;

public class UserCommand {
  static final int MAX_SIZE = 10;
  static User[] users = new User[MAX_SIZE];
  static int userLength = 0;

  static void excuteUserCommand(String command) {
    System.out.printf("[%s]\n", command);
    switch (command) {
      case "등록":
        addUser();
        break;
      case "목록":
        listUser();
        break;
      case "조회":
        viewUser();
        break;
      case "변경":
        updateUser();
        break;
      case "삭제":
        deleteUser();
        break;
    }
  }

  static void addUser() {
    User user = new User();
    user.name = prompt.input("이름?");
    user.email = prompt.input("이메일?");
    user.password = prompt.input("암호?");
    user.tel = prompt.input("연락처?");
    users[userLength++] = user;
  }

  static void listUser() {
    System.out.println("번호 이름 이메일");
    for (int i = 0; i < userLength; i++) {
      User user = users[i];
      System.out.printf("%d %s %s\n", i + 1, user.name, user.email);
    }
  }

  static void viewUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    System.out.printf("이름 : %s\n", user.name);
    System.out.printf("이메일 : %s\n", user.email);
    System.out.printf("연락처 : %s\n", user.tel);
  }

  static void updateUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    User user = users[userNo - 1];
    user.name = prompt.input(String.format("이름(%s):", user.name));
    user.email = prompt.input(String.format("이메일(%s):", user.email));
    user.password = prompt.input(String.format("비밀번호(%s):", user.password));
    user.tel = prompt.input(String.format("연락처(%s):", user.tel));
    System.out.println("변경했습니다.");
  }

  static void deleteUser() {
    int userNo = Integer.parseInt(prompt.input("회원번호?"));
    if (userNo < 1 || userNo > userLength) {
      System.out.println("없는 회원입니다.");
      return;
    }
    for (int i = userNo; i < userLength; i++) {
      users[i - 1] = users[i];
    }
    userLength--;
    users[userLength] = null;
    System.out.println("삭제했습니다.");
  }
}