오늘 개인과제를 선택항목까지 모두 구현 후 제출했다.
어제와 오늘 코드를 구현하는 중 겪었던 문제에 대해 적어보려한다.
1차로 필수기능구현까지 다 했을때 코드의 메인 동작들이 Kiosk 클래스로 몰렸고, 내부 로직이 아래와 같이 구성되어있었다
메인 메뉴화면 >> 상품메뉴 화면 or 장바구니 화면 or 주문취소 화면 >>
(각자 화면에서 선택지를 주고 화면끼리 핑퐁하는 식)
이런 코드는 코드 확장성이 좋지않고, 기능을 추가하거나 예외처리를하기 어려울듯 하여 선택기능을 구현하기 전에 리팩터링을 했다. 1차로 코드를 짤 때까지는 과제항목만 보고 대강의 흐름만 그린 상태에서 코드를 짰었다. 이 방식은 아닌것 같아서 서치를 하다가 약식으로 기능 명세서 작성하기란 포스팅을 발견했다.
(지금 다시 검색해보니 지금한 것도 막 한것 같아보이긴한데...)
어떤 객체가 있을건지, 이 객체는 다른객체랑 어떤 상호작용을 하는지, 이 객체가 하는 행동은 무엇인지 등등을 적어보고, 한 작업들은 체크하는 형식으로 작업을 진행하는 방법이었다.
이 점을 참고해서 README.md파일에 구현할 객체들을 생각해보고, 이 객체가 무슨일을 할것인지를 정리해봤다.
이렇게 각 객체가 하는 일들을 글로 정리해보니 어떻게 작업을 나눌지, 어떤 클래스를 만들것이고, 어떤 메서드를 작성할것인지가 눈에 보여 작업진척도가 빨라졌다.
또한 Kiosk에 입력, 출력 기능들이 모두 모여있었고, 코드가 어떻게 진행되는지 한 눈에 알아보기 힘들었던 이전과 달리 Kiosk의 작업상태를 나타내는 status란 변수를 두고, 각 상태에따라 입력, 출력이 하는 일을 Kiosk가 컨트롤 하는 식으로 코드를 정리했다.
또한 status는 코드를 알아보기 쉽게 상수값으로 각 상태를 나타내어 가독성을 좋게 수정했다. 이렇게 수정 하니 코드 확장성, 기능추가를 할 때 시간이 덜 걸려서 좋았다.
주문을 완료한 화면에서 3초의 대기시간이 발생하는데,
다른 화면들에서는 입력값을 받기 때문에 문제가 없었던 반면, 이 주문완료 화면에서는 사용자가 값을 입력했을 때 그 값이 버퍼에 남아있어 메인화면에서 버퍼에 남은 값들을 입력값으로 받고 알아서 화면이 넘어가는 문제를 발견했다.
버퍼에 남은 값을 비워주면 될 것 같아 처음에는 스캐너의 퍼버값을 날려주는
nextLine() 메서드를 쓰면 될 것 같아, 메인 메뉴로 돌아가기전 아래 메서드를 동작하게 하도록 수정했는데,
public void receiveClean(){
Scanner scanner = new Scanner(System.in);
scanner.nextLine
}
이렇게 하니 주문을 완료한 화면일때 입력을 해도 메인메뉴로 넘어갈때 버퍼값이 안남아있어서 작동에 문제가 없었다.
그런데, 이렇게 입력을 받으니 3초가 지나도 입력값이 없으면 화면이 넘어가지 않았다ㅎ..
그래서 Scanner의 메서드중 버퍼에 값이 있는지 확인 하는 메서드를 사용해서 코드를 짜면 되지 않을까 싶어 hasNext() 메서드를 사용해서 코드를 짜봤으나, 마찬가지로 입력값이 들어가기전까지 무한대기상태가 되었다.
왜 그런가 싶어 찾아보니 Scanner는 사용자로부터 입력을 대기하며, 입력이 발생하기 전까지 코드 실행이 차단된다고 한다.
그래서 Scanner 라이브러리로는 문제를 해결할 수 없겠다 싶던차에, 또 다른 입력방법으로 BufferedReader 라이브러리를 찾았다.
BufferedReader는 내부적으로 버퍼를 사용하여 데이터를 읽어온다. 이는 입출력 작업의 효율성을 높이는데 도움이 되고 데이터를 한 번에 읽어와서 버퍼에 저장한 후, 필요할 때마다 버퍼에서 데이터를 읽어온다. 이를 통해 입출력 작업의 빈번한 호출을 줄여 성능을 향상시킨다.
따라서 입력대기 혀상은 일어나지 않는것!
그래서 위의 로직은 그대로 하되 Scanner의 hasNext()를 BufferedReader의 ready()로, nextLine()->readLine()으로 변경하여 코드를 수정했고,
정상적으로 주문완료화면에서 입력을 받든 안 받든 넘어가고, 추가입력도 없겠끔 바꿨다.
public void receiveClean() throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
if(br.ready()){
br.readLine();
}
}
과제 해설 영상을 보고 상품을 배열에 넣지 않고 List에 넣어서 작업한 후, hashMap을 사용했으면 지금보다 코드가 더 깔끔해질 수 있단 단서를 얻었다.
원래는 상품과 메뉴가 이미 정해진 상태에서 나가는 목록이라 생각해서 그냥 배열로 항목들을 묶었는데,
이후 추가 구현을 하게된다는 것을 가정해보면 List로 구현하고, 상품이나 메뉴가 늘어날 것을 고려해 hashMap을 쓰는게 더 좋겠단 생각이 들었다.
나중에 시간이 되면 해당부분을 리팩터링 해봐야겠다.
class를 나누다 보니 머리아파지는 부분이 바로 접근제어자였다. 캡슐화, 정보보안등을 고려해 private와 public등의 접근제어자를 설정했는데 다 짜고나서 보니 목표했던 데로 움직이지 않는 클래스들이 보였고(인스턴스를 사용할 부분이었는데 구현을 하다보니 static처럼 사용되고있는 메서드), static변수와 인스턴스 변수, 메서드들이 섞여 지금봐도 리팩터링해야할 부분이 눈에 보인다. 다음 과제에서는 이번에 애먹었던 부분들을 고려해서 접근제어자를 설정해야겠다.
최대한 객체지향이란 특성에 맞게 짜보려고 노력해봤으나 아직 한참멀었다는 생각이 들었다. 객체지향 방법론에 대해 공부할 필요성을 느꼈다.