본문 바로가기
네이버클라우드/JAVA 웹 프로그래밍

JAVA 21일차 (2023-06-21) 자바 기초 DAY19_Composite 패턴을 활용하여 메뉴 구현_개인프로젝트 - 마트 관리 시스템

by prometedor 2023. 6. 22.
## 23. Composite, Command, Observer 디자인 패턴, 추상 클래스/메서드 활용하기

- Composite 패턴을 활용하여 메뉴 구현하기
  - BreadcrumbPrompt에 적용
  - Menu, MenuGroup 클래스 정의

ㄴ 폴더가 폴더를 담을 수 있음 => 메뉴도 메뉴를 담을 수 있음

 

Composite 패턴

ㄴ 구조패턴(Structural Patterns)에 있는 Composite(합성패턴)

ㄴ 객체들의 관계를 트리구조로 구성하여 부분-전체 계층을 표현하는 패턴

 

bitcamp.util 패키지에 Menu 클래스 생성

 

테스트를 위해 패키지 P1 생성

ㄴ bitcamp.test 패키지에 p1 패키지 생성

 

ㄴ 생성한 p1 패키지에 A 클래스를 생성

 

A.java

ㄴ 접근제어자 테스트 위해 A 클래스 생성

 

Test1.java

ㄴ private 으로 선언된 인스턴스 필드 v1 는 접근 불가

 

Test2.java

ㄴ bitcamp.test 패키지에 Test2 클래스 생성

ㄴ A 클래스와 패키지가 다르므로 private 으로 선언된 인스턴스 필드 v1, default 로 선언된 인스턴스 필드 v2, protected 로 선언된 인스턴스 필드 v3는 접근 불가

 

Test3.java

ㄴ bitcamp.test 패키지에 Test3 클래스 생성

 

Test3.java

ㄴ A 클래스와 패키지가 다르므로 private 으로 선언된 인스턴스 필드 v1, default 로 선언된 인스턴스 필드 v2는 접근 불가

ㄴ Test3 클래스가 A 클래스를 상속은 받았지만 obj 는 A 클래스의 인스턴스를 생성하므로 obj 로 다른 패키지에 있는 A 클래스의 protected 로 선언된 v3 인스턴스 필드는  접근 불가

ㄴ m() 도 상속받은 멤버가 아니므로 접근 불가

 

A.java

ㄴ m() 메서드의 접근제어를 protected 로 변경

 

Test2.java

ㄴ A 클래스의 m() 메서드는 같은 패키지도 아니고 서브 클래스도 아니므로 접근 불가

 

Test3.java

ㄴ m2() 는 같은 스태틱 멤버이므로 그냥 호출 가능

 

Composite 패턴을 활용하여 메뉴 구현하기

BreadcrumbPrompt에 적용 및 Menu, MenuGroup 클래스 정의

Menu.java

ㄴ title 을 받는 생성자 추가

 

Menu.java

ㄴ title 이 private 이므로 getter 를 이용해 title 을 받아올 수 있도록 함

 

Menu.java

 

App.java

ㄴ 생성한 Menu 클래스 사용하기 위해 import 해주기

 

Menu.java

ㄴ 메뉴를 실행할 메서드 execute() 생성

 

MenuGroup.java

ㄴ bitcamp.util 패키지에 MenuGroup 클래스 생성

=> bitcamp.util 패키지에 있는 ArrayList 클래스를 사용하고 Menu 클래스를 상속받도록 함

 

MenuGroup.java

ㄴ MenuGroup 클래스의 생성자에서는 super 키워드를 사용하여 상위 클래스인 Menu 클래스의 생성자를 호출해야 함

=> super() 생성자를 호출하는 코드를 작성하지 않으면 컴파일러가 자동으로 수퍼 클래스인 Menu 클래스의 기본 생성자를 호출함

ㄴ 하지만 현재, 수퍼 클래스인 Menu 클래스에서 default constructor 가 정의되지 않아서 에러 발생

=> 암시적 슈퍼 생성자 Menu()가 정의되지 않아 다른 생성자를 명시적으로 호출해야 함

• Student(){…}; => 자신의 필드만 초기화 시킴
  => Member() 를 상속하고 있으므로 super(); 를 호출해줘야 함

• super(); 를 컴파일러가 자동 삽입하는데,수퍼 클래스에 기본생성자가 없으면 
  자식 클래스에서 명시적으로 선언해줘야 함

•super(); 문장은 생성자의 가장 처음에 작성되어야 함

 

 

MenuGroup.java

=> ArrayList menu = new ArrayList(); 코드를 생성자 바깥쪽에 생성해도 컴파일 시 아래처럼 변경되어 실행됨

ㄴ menu 변수에는 새로운 ArrayList 객체가 할당됨
=> MenuGroup 클래스의 객체를 생성할 때 title 값을 전달하여 초기화할 수 있으며, menu 변수는 빈 ArrayList로 초기화됨

 

MenuGroup.java

ㄴ 보통 자식 클래스를 의미하는 childs 라는 이름의 변수를 사용

=> 일반적으로 메뉴 그룹은 다른 메뉴들을 포함할 수 있으므로, childs 리스트는 해당 그룹에 속한 메뉴들을 저장함
ㄴ addMenu(Menu menu) 메서드를 생성하여 ArrayList 클래스의 add(Object obj) 메서드를 사용하도록 코드 작성

 

MenuGroup.java

ㄴ Menu 클래스에 있는 execute() 메서드를 재정의(Overriding)

=> execute() 메서드 실행 시 Menu 객체 menu 에 childs 변수에 저장된 자식 메뉴들을 순회하면서 각 메뉴의 제목 출력

=> 마지막으로 "0. 이전/종료" 메뉴를 출력

 

App.java

ㄴ MenuGroup 클래스 사용하기 위해 코드 작성

 

App.java

ㄴ MenuGroup 객체인 main을 생성 ("메인"이라는 title 을 가지고 있음)

ㄴ main에 세 개의 자식 메뉴를 추가 (각각 "직원", "물품", "게시글", "공지"이라는 title을 가진 Menu 객체)
=> main은 "메인" 메뉴 그룹을 나타내고, 그 아래에 "직원", "물품", "게시글", "공지" 네 개의 자식 메뉴가 포함되어 있는 구조

 

App.java

ㄴ 잠시 해당 블럭 주석으로 막아두기

 

App.java

ㄴ main -> mainMenu로 변수명 변경 후 MenuGroup 의 인스턴스 변수 mainMenu 가 가리키는 MenuGroup 클래스의 execute() 를 실행함

 

App.java

ㄴ prompt 를 파라미터로 추가하여 getMenu() 를 각각 호출할 수 있도록 만들어줌

=> prompt 의존객체를 생성자에 넘겨줌

 

Menu.java

ㄴ MenuPrompt 파라미터를 추가해줌

 

MemberGroup.java

ㄴ execute 메서드에 MenuPrompt 파라미터 추가

ㄴ 현재 MenuGroup 객체의 타이틀을 prompt에 추가

ㄴ getTitle() 메서드는 현재 MenuGroup 객체의 타이틀을 반환

ㄴ null은 해당 메뉴를 선택했을 때 실행할 핸들러가 없음을 나타냄 (주석 막아놨으므로 일단 null 로 설정)

 

MemberGroup.java

ㄴ Menu 출력 형식 부분을 printMenu() 메소드로 분리

 

MemberGroup.java 

ㄴ prompt.inputMenu() 로 받아온 String 타입을 int 타입으로 변환시켜 menuNo 에 넣음

ㄴ 해당 번호가 0보다 작거나 childs 리스트의 크기보다 크다면 "메뉴 번호가 옳지 않습니다" 출력하도록 함

ㄴ 해당 번호가 0이라면 prompt.removeBreadcrumbs(); 코드를 실행하고 호출한 곳으로 리턴됨

ㄴ 해당 번호가 0 과 childs 리스트의 크기 사이의 값이라면 ArrayList 의 get(int index) 를 이용하여 해당 번호에 대한Object 값을 가져옴 => Menu 타입으로 형변환 해줘야 함, 종료를 제외한 menuNo 는 1부터 시작이므로 menuNo - 1 을 해줘야 함

 

MemberGroup.java 

ㄴ 무한 루프를 추가해줘서 0일 경우만 무한루프를 나가도록 만듦

 

MemberGroup.java 

ㄴ 입력 문자열이 "menu" 와 같다면 printMenu() 를 실행하도록 하고 continue; 를 이용해 다시 while문의 처음으로 가서 무한반복

 

MenuPrompt.java

ㄴ menus 스택 선언을 제거

 

MenuPrompt.java

ㄴ appendBreadcrumbs 메서드의 파라미터 String menu도 제거해야됨

ㄴ 선택한 내용 모두 제거

 

MenuPrompt.java

ㄴ inputMenu() 메서드의 리턴값 수정

 

MenuPrompt.java -> BreadcrumbPrompt.java

ㄴ MenuPrompt -> BreadcrumbPrompt 로 변경(Refactor 이용)

 

MenuGroup.java

=>

 

App.java

=>

ㄴ getMenu() 지우기

 

App.java

ㄴ 해당 코드 제거

 

App.java

=>

ㄴ prompt 모두 제거

 

App.java

ㄴ MenuGroup 객체 mainMenu 의 execute 메서드에 아규먼트로 prompt 를 전달함

 

현재 상태에서 테스트 실행

 

BoardcrumbPrompt.java

=>

ㄴ addMenu -> add 로 변경 (Refactor 이용)

 

App.java

ㄴ 임시적으로 주석 막아뒀던 코드 완전히 제거

 

App.java

ㄴ prompt 적용