프로젝트 - Waiter<음식점 예약 프로그램>

송진영·2022년 5월 10일
0

프로젝트

목록 보기
1/1

프로젝트 깃허브 주소
https://github.com/jinyeong-afk/3-Grade-Project-Waiter

[목차]

[1. 프로젝트 개요]

[2. 사용 언어 및 기술]

[3. 담당 역할]

[4. 담당 소스 코드]

[4.1 커맨드 패턴]

[4.2 데코레이터 패턴]

[4.3 메멘토 패턴]

[5. 테스트]

[5.1 커맨드 패턴 테스트]

[5.2 데코레이터 패턴 테스트]

[5.3 메멘토 패턴 테스트]

[6. 배운점 및 아쉬운점]

프로젝트 개요

인기 많은 식당에서 테이블이 꽉 차 있으면 식당 앞에서 번호표를 뽑아서 기다려야 하는데 ‘웨이터’ 프로그램을 통해서 원격으로 예약할 수 있도록 제작하였다. 손님은 매장 정보들을 검색하고 메뉴, 시간을 정하여 예약하면 테이블의 정보를 받아와 예약을 진행하고 만약 대기 시간이 있는 경우 기다려야하는 시간을 알려준다. 매장관리자는 등록한 매장에 대한 정보를 수정하거나 추가할 수 있고 가게 내의 서빙과 관련된 기능을 통해 현재 매장의 손님 조회 및 조회한 손님의 음식 값을 결제하는 등의 편의 기능을 제공한다. 따라서 이용자는 매장 앞에서 기다리지 않고 프로그램을 통해 음식점을 예약할 수 있으며, 매장관리자는 서빙과 관련된 기능을 통해 효율적으로 가게를 운영할 수 있다.

사용 언어 및 기술

  • Language: Java
  • IDE: Apache NetBeans IDE
  • Database: Oracle
  • 주요 기술: 디자인 패턴
    • Builder Pattern
    • State Pattern
    • Observer Pattern
    • Factory Method Pattern
    • Command Pattern
    • Memento Pattern
    • Decorator Pattern
    • Template Method

담당 역할(구성원 5명)

  1. 커맨드 패턴을 적용한 결제 서비스
  2. 데코레이터 패턴을 적용한 할인 서비스
  3. 메멘토 패턴을 적용한 결제 오류 처리

담당 소스 코드

1. 커맨드 패턴 적용

커맨드 패턴은 실행될 기능을 캡슐화 함으로써 주어진 여러 기능을 실행할 수 있는 재사용성이 높은 클래스를 설계하는 패턴 즉, 이벤트가 발생했을 때 실행될 기능이 다양하면서도 변경이 필요한 경우에 이벤트를 발생시키는 클래스를 변경하지 않고 재사용하고자 할 때 유용하다.
실행될 기능을 캡슐화 함으로써 기능의 실행을 요구하는 호출자(Invoker) 클래스와 실제 기능을 실행하는 수신자(Receiver) 클래스 사이의 의존성을 제거한다.
따라서 실행될 기능의 변경에도 호출자 클래스를 수정 없이 그대로 사용 할 수 있도록 해준다.

                                   <Command Pattern 클래스 다이어그램>

1.1 문제점

유스케이스 “결제”에 대해 Command Pattern을 적용한다.
우선 요금 결제 부분에는 결제 진행 알림, 음식 값 더하기, 음식 값에서 받은 돈 빼기, 결제 상태 알림 등의 다양한 기능들이 있다. 결제 수단에는 현금 결제와 카드 결제 두 가지 수단이 있고, 뿐만 아니라 새로운 결제 수단이 추가 될 수도 있는데 매 결제 수단마다 위에서 언급한 결제에 관련된 기능들을 적용시키면 코드 중복이 발생해 수정이나 디버깅 이슈가 발생할 가능성이 높아질 수 있다. 또한, 새로운 기능을 추가할 때 기존의 코드를 수정해야 하는 문제가 발생하여 개방-폐쇄 원칙(OCP, Open-Closed Principle)과 단일 책임 원칙(SRP, Single-Responsibility-Principle)이 위배될 수 있다.

1.2 해결 방안

                   <Command Pattern을 적용한 결제 기능의 클래스 다이어그램>

Command Pattern을 사용하면 결제에 관련된 각 기능들을 ConcreteCommand에 해당하는 각각 Pay Command (결제 진행 알림), AddAmountCommand(음식 값 더하기), SubAmountCommand(음식 값에서 받은 돈 빼기), CompletionCommand(결제 상태 알림) 객체로 캡슐화 해서 코드의 중복을 방지할 수 있다. 그리고 Command의 세부 기능을 수행하는 Receive와 작업을 요청하는 Invoke 객체를 분리하기 때문에 단일 책임 원칙(SRP, Single-Responsibility-Principle)을 지켜낼 수 있고, 기존 코드 수정 없이 새로운 Receive, 명령어 추가가 가능하기 때문에 개방-폐쇄 원칙(OCP, Open-Closed Principle)을 잘 지켜낼 수 있다. 커맨드 단위의 별도의 액션(execute) 등이 가능하고 커맨드 상속 및 조합을 통해 더 정교한 커맨드를 구현할 수 있다.

1.3 관련 코드 설명

소스파일 목록은 다음과 같다.

중요 코드들은 다음과 같다.

1.3.1 PaymentCommand.java

이 인터페이스는 실행될 기능에 대한 인터페이스로, 실행될 기능을 execute 메소드로 선언했다.
이 인터페이스는 커맨드 패턴에서 Command 부분이다.

1.3.2 AddAmountCommand.java

이 클래스는 Command 인터페이스를 구현한 것으로, 손님이 먹은 음식의 값들을 ArrayList로 받아서 값들을 다 더하는 Command를 구현한 것이다.
이 클래스는 커맨드 패턴에서 ConcreteCommand 부분이다.

1.3.3 SubAmountCommand.java

이 클래스는 Command 인터페이스를 구현한 것으로, 결제해야 하는 금액에서 지불하는 금액을 빼줘서 거스름돈을 반환하는 Command를 구현한 것이다.
이 클래스는 커맨드 패턴에서 ConcreteCommand 부분이다.

1.3.4 PayCommand.java

이 클래스는 Command 인터페이스를 구현한 것으로, 결제 진행을 알리는 Command를 구현한 것이다. 이 클래스는 커맨드 패턴에서 ConcreteCommand 부분이다.

1.3.5 CompletionCommand.java

이 클래스는 Command 인터페이스를 구현한 것으로, 결제 상태를 알리는 Command를 구현한 것이다. 이 클래스는 커맨드 패턴에서 ConcreteCommand 부분이다.

1.3.6 Invoke.java

이 클래스는 커맨드의 execute() 메소드를 호출함으로써 커맨드 객체에게 특정 작업을 호출하는 호출자 클래스이다. 이 클래스는 커맨드 패턴에서 Invoker 부분이다.

1.3.7 Receive.java

이 클래스는 ConcreteCommand에 해당하는 클래스들의 세부적인 기능을 담당하는 수신자 클래이다. 이 클래스는 커맨드 패턴에서 Receiver 부분이다.


2. 데코레이터 패턴 적용

데코레이터 패턴은 객체의 결합을 통해 기능을 동적으로 유연하게 확장할 수 있게 해주는 패턴으로, 기본 기능에 추가할 수 있는 기능의 종류가 많은 경우게 각 추가 기능을 Decorator 클래스로 정의한 후 필요한 Decorator 객체를 조합함으로써 추가 기능의 조합을 설계하는 방식이다.
기본 기능에 추가할 수 있는 많은 종류의 부가 기능에서 파생되는 다양한 조합을 동적으로 구현할 수 있다.

2.1 문제점

유스케이스 “회원 할인”에 대해 Decorator Pattern을 적용한다.
결제를 진행할 때 멤버쉽 기능에 추가적으로 고객의 등급에 따라 할인을 다르게 적용시키는 부가적인 기능을 추가하는데, 거기에 더해 추후에 새로운 새로운 할인 적용 방법을 추가할 때, 많은 자식 클래스들이 생성되면서 부모 클래스에 멤버 변수들이 계속 추가되는 등의 이유로 나중에 해당 기능을 추가 삭제시킬 때 중심이 되는 객체를 수정해야 한다는 문제점이 발생해 개방-폐쇄 원칙(OCP, Open-Closed Principle)을 지켜내지 못하게 된다.

2.2 해결 방안

Decorator 패턴을 사용하면 동일한 객체를 여러 개 만들어야 하지만 각기 다른 기능을 첨가할 필요가 있을 때 많은 객체에게 다양한 부가 기능을 쉽고 빠르게 적용할 수 있다. 따라서 중심이 되는 Membership 객체는 놔두고 Membership Component에 따른 Bronze, Silver, Gold, Platinum 등의 추가적인 사항을 첨가하게 되어서 객체에 기능을 추가 또는 삭제할 때 Membership 객체는 수정하지 않고 동적으로 추가 또는 삭제할 수 있어서 개방-폐쇄 원칙(OCP, Open-Closed Principle)을 지킬 수 있게 된다.

2.3 관련 코드 설명

소스 파일 목록은 다음과 같다.

2.3.1 Membership.java

이 추상 클래스는 price와 type 변수는 캡슐화 해주고, 가격 출력 함수와, 멤버쉽 출력 함수를 추상 함수로 만들었다. 이 클래스는 데코레이터 패턴에서 Component 부분이다.

2.3.2 Guest.java

이 클래스는 Membership을 상속받아 Membership을 이용하는 Guest 고객 객체를 만들어 추상 함수를 가격과 타입을 출력해주는 함수로 정의하였다. 이 클래스는 데코레이터 패턴에서 ConcreteComponent 부분이다.

2.3.3 MembershipCardDecorator.java

이 추상 클래스는 Membership을 상속받아 추상 함수 getType을 만들었다.
이 클래스는 데코레이터 패턴에서 Decorator 부분이다.

2.3.4 Bronze.java

이 클래스는 Membership Decorator를 상속받아 Guest에 더해 Bronze 등급에 따른 할인 적용과 타입 출력 기능을 추가시킨다.
이 클래스는 데코레이터 패턴에서 ConcreteDecorator 부분이다.

2.3.5 Silver.java

이 클래스는 Membership Decorator를 상속받아 Guest에 더해 Silver 등급에 따른 할인 적용과 타입 출력 기능을 추가시킨다.
이 클래스는 데코레이터 패턴에서 ConcreteDecorator 부분이다.

2.3.6 Gold.java

이 클래스는 Membership Decorator를 상속받아 Guest에 더해 Gold 등급에 따른 할인 적용과 타입 출력 기능을 추가시킨다.
이 클래스는 데코레이터 패턴에서 ConcreteDecorator 부분이다.

2.3.7 Platinum.java

이 클래스는 Membership Decorator를 상속받아 Guest에 더해 Platinum 등급에 따른 할인 적용과 타입 출력 기능을 추가시킨다.
이 클래스는 데코레이터 패턴에서 ConcreteDecorator 부분이다.


3. 메멘토 패턴 적용

메멘토 패턴은 객체를 이전 상태로 되돌릴 수 있는 기능을 제공하는 패턴이다.

메멘토 패턴에는 두 가지 목적이 있다.

  • 시스템에서 핵심적인 기능을 담당하는 객체의 중요한 상태 저장
  • 핵심적인 객체의 캡슐화 유지

3.1 문제점

유스케이스 “결제 오류”에 대해 Memento Pattern을 적용한다.
결제를 진행할 때 음식 값을 더하는 기능과 결제해야 하는 금액에서 지불한 금액을 빼는 기능을 커맨드 패턴으로 객체화 해서 진행하는데 결제해야 하는 금액에서 지불한 금액을 뺄 때 카드는 보다 많은 금액을 지불할 수가 없기 때문에 오류를 발생했을 때나 결제를 취소하는 기능을 추가할 경우 이전의 값으로 되돌리는 것에 대한 해결점을 찾는 문제가 발생한다.

3.2 해결 방안

메멘토 패턴을 이용해서 결제해야 하는 금액에서 지불한 금액을 빼기 전에 고객 객체의 정보(지불 금액 및 지불해야 할 금액)를 저장하여 핵심 객체와는 다른 별도의 객체에 보관하여 정보의 안전성을 높이고, 결제 오류가 발생했을 경우 고객 객체의 정보를 복구할 수 있다. 핵심 객체의 데이터를 계속해서 캡슐화된 상태로 유지할 수 있다

3.3 관련 코드 설명

소스 파일 목록은 다음과 같다.

3.3.1 Client.java

이 클래스는 현재 객체의 정보 값인 AmountPaid와 AmountNotPaid, payCheck 값을 저장하는 Memento 객체를 생성하고 돌려주는 createMemento 함수가 정의 되어 있고, Memento 객체로 전달된 상태를 복구하는 RestoreMemento 함수가 정의되어 있다.
이 클래스는 메멘토 패턴에서 Originator 부분이다.

3.3.2 PaymentMemento.java

이 클래스는 Client가 저장 및 복원하려는 정보(AmountPaid, AmountNotPaid, payCheck)를 가지고 있는 패턴 객체이다.
이 클래스는 메멘토 패턴에서 Memento 부분이다.

3.3.3 CareTaker.java

이 클래스는 Client의 정보(AmountPaid, AmountNotPaid, payCheck)를 Stack형태로 push를 이용해서 쌓고, pop을 이용해서 반환을 해준다.
이 클래스는 메멘토 패턴에서 CareTaker 부분이다.

테스트

1 “Command Pattern” 테스트

1.1 관련 테스트 코드

Command_Test.java

커맨드 패턴을 사용해서 결제를 진행할 때 각 기능들을 캡슐화 해서 각각의 기능과 Invoker와 Receive가 잘 진행되는지 테스트를 하기 위해서 Command_Pattern 패키지를 Command_Test 클래스에서 실행을 해보았다. 다음과 같이 실행하면 커맨드 각 기능이 잘 동작을 하는지 확인할 수 있다.

1.2 테스트 실행 결과

Command_Test.java 실행결과

PayCommand (결제 시작 알림), AddAmountCommand (음식 값 더하기), SubAmountCommand(값 빼기), CompletionCommand(결제 상태 알림), Invoker(커맨드 지정), Receive(커맨드 세부 기능)이 잘 작동하여 테스트가 성공한다.


2. “Decorator Pattern” 테스트

2.1 관련 테스트 코드

Decorator_Test.java

데코레이터 패턴의 ConcreteDecorator가 잘 동작하는지 확인하기 위해서 Decorator_Pattern 패키지에서 Decorator_Test 클래스를 실행해보았다. 다음과 같이 진행해보면 데코레이터 패턴이 잘 동작하는지 확인할 수 있다.

2.2 테스트 실행 결과

Decorator_Test.java 실행결과

각 ConcreteDecorator들이 다음과 같이 잘 동작하는 것을 확인할 수 있어 테스트가 성공하였다.


3. “Memento Pattern” 테스트

3.1 관련 테스트 코드

Memento_Test.java

객체의 정보를 저장하여 원하는 시점에 잘 불러와지는지 확인하기 위해서 Memento_Pattern 패키지에서 Memento_Test 클래스에서 실행을 해보았다. 다음과 같이 진행해보면 메멘토 패턴이 잘 동작하는지 확인할 수 있다.

PaymentMementoTest.java

TestPackages 패키지에서 junit을 활용한 메멘토 패턴 단위 테스트를 진행해보았다.

3.2 테스트 실행 결과

Memento_Test.java 실행결과

PaymentMementoTest.java 실행결과

오류가 발생해 메멘토 패턴을 이용해서 오류 발생 이전 객체 저장한 값을 불러와지는데 성공해 테스트를 성공했다.

배운점 및 아쉬운점

기존 프로젝트들과 다르게 처음으로 디자인 패턴을 적용한 프로젝트를 진행하였는데 디자인 패턴을 적용하니 팀원들과 역할을 나눠 설계를 하는 것에 용이했고, 또한 처음 설계와 달라진 부분에 대하여 유연하게 대처할 수 있어서 좋았다. 또한, 소스 코드의 낭비 없이 깔끔한 소스 코드를 작성할 수 있어 팀원들과 소스 코드 리뷰 하기에 편했다.

아쉬운 점은 디자인 패턴을 3개를 구현하여 내가 구현했던 커맨드, 데코레이터, 메멘토 패턴에 대한 이해도는 얻을 수 있었지만 나머지 팀원들이 구현한 패턴들은 시간이 부족해서 이해하지 못하고 넘어갔다. 이부분에 대해서는 따로 공부를 해야 할 것 같다.

profile
못하는 건 없다. 단지 그만큼 노력을 안 할 뿐이다.

0개의 댓글