커피를 통해 배우는 OOP - 2

suky·2021년 8월 18일
1

안녕하세요~ suky입니다.
지난번에 이어서 이번에는 코드를 통해서 OOP에 대하여 좀 더 알아보려고 하는데요.
이번에 사용된 용어에 대하여서는 1편을 참고하시면 좋을 것 같습니다. (앗! 1편에 안 나온 용어가 있으면 피드백 주시면 감사합니다 😁)
커피를 만들어지는 과정을 통해 어떤 것이 객체일지 생각해보고, 어떻게 설계를 해야할지 알아봅시다.

커피 한 잔 할래요?

커피는 어떻게 만들어질까?

개발자의 일상이라 하죠? 아침에 눈을 뜨고,,, 지친 몸을 이끌고 회사로 출근합니다.
앗! 오늘은 카페인이 부족하다고 느껴진다면 근처 카페에 가죠.
카페에 가서 메뉴판을 보고 바리스타께 요청합니다. '아이스 아메리카노 레귤러 사이즈 하나 주세요.'

치익,,, 바리스타는 에스프레소를 내린 뒤 차가운 얼음이 든 컵에 에스프레소를 끼얹고 말합니다.
'주문하신 아이스 아메리카노 레귤러 사이즈 나왔습니다.'

이것이 아마 일반적으로 커피가 만들어지는 과정이라고 생각합니다. (물론,,, 제 개인적인 경험에 의해서 각색했습니다 😂)

무엇이 객체일까?

앞서 1편에서는 객체란 인지할 수 있는 존재나 개념이라고 생각했습니다.
그럼 찾아볼 수 있는 모든 객체를 정리해볼까요?

  • 개발자
  • 회사
  • 오늘
  • 카페인
  • 카페
  • 메뉴판
  • 바리스타
  • 아이스 아메리카노
  • 에스프레소
  • 차가운 얼음

등이 있겠네요.
커피를 내리는 과정에서 이중에 꼭 필요하다고 생각하는 가장 추상적이고 핵심적인 객체는 다음과 같다고 생각합니다.

  • 개발자 (손님)
  • 메뉴판
  • 바리스타
  • 아이스 아메리카노 (커피)

결국 위에 예제에서 한 행동은 개발자가 메뉴판을 보고 바리스타에게 커피를 주문 후 받는 행동을 했다고 판단해서 위와 같이 정리했습니다.

객체 간의 관계

협력 만들기

객체 간에는 어떤 관계가 있을까요? 이해하기 쉬운 방식으로 표현해봅시다.

간단하게 나온 객체들을 위와 같이 아무런 협력과, 책임 없이 역할만 표현했습니다.
이제 개발자가 메뉴판을 보고 바리스타에게 커피를 주문 후 받는 행동을 했다를 표현해볼까요?

관계가 눈에 보이시나요? 설계라고 하기에는 조잡하지만 그럴싸한 설계가 완성된 것 같습니다 😁
위와 같이 객체들 간의 메시지 전달과 수신을 표현한 것을 협력이라고 하고, 객체와 객체가 연결된 것을 링크(link)되었다라고 합니다.

기본 코드 작성

위의 객체들을 클래스로 작성해보도록 하겠습니다.
책임 위주의 구현을 할 예정이니 참고해주세요!

class Customer {}
class MenuBoard {}
class Baristar {}
class Coffee {}

단순하죠? 이제 대략적인 책임을 넣어주도록 해보겠습니다.

class Customer {
  order = () => {}; // 메뉴판을 확인하고, 바리스타로부터 커피 주문
}

class MenuBoard {
  init = () => {}; // 메뉴를 초기화
  getMenu = () => {}; // 메뉴를 제공
}

class Baristar {
  makeCoffee = () => {}; // 커피를 생산
}

class Coffee {}

커피도 종류가 여러가지가 있어야겠죠? Coffee 객체를 상속하여 아메리카노, 카푸치노, 카페라떼 3가지를 만들어보도록 하겠습니다.

class Customer {
  order = () => {}; // 메뉴판을 확인하고, 바리스타로부터 커피 주문
}

class MenuBoard {
  init = () => {}; // 메뉴를 초기화
  getMenu = () => {}; // 메뉴를 제공
}

class Baristar {
  makeCoffee = () => {}; // 커피를 생산
}

class Coffee {}
class Americano extends Coffee {}
class Cappuccino extends Coffee {}
class CaffeLatte extends Coffee {}

세부 코드 작성

먼저 메뉴판을 초기화해보록 하죠!

class MenuBoard {
  constructor() {
    this.menuList = null;
  }
  init = (menuList) => {
    this.menuList = menuList;
  }; // 메뉴를 초기화
  getMenu = (menu) => this.menuList.find((m) => m.name === menu); // 메뉴를 제공
}

손님은 메뉴판을 보고 바리스타께 요청해볼까요?

class Customer {
  order = (menu, menuBoard, baristar) => {
    const menuItem = menuBoard.getMenu(menu);
    const coffee = baristar.makeCoffee(menuItem);
  }; // 메뉴판을 확인하고, 바리스타로부터 커피 주문
}

이제 바리스타가 커피를 생산하면 끝이네요!

class Baristar {
  makeCoffee = (coffee) => new coffee(); // 커피를 생산
}

정리를 하면 다음과 같습니다!

class Customer {
  order = (menu, menuBoard, baristar) => {
    const menuItem = menuBoard.getMenu(menu);
    const coffee = baristar.makeCoffee(menuItem);
  }; // 메뉴판을 확인하고, 바리스타로부터 커피 주문
}

class MenuBoard {
  constructor() {
    this.menuList = null;
  }
  init = (menuList) => {
    this.menuList = menuList;
  }; // 메뉴를 초기화
  getMenu = (menu) => this.menuList.find((m) => m.name === menu); // 메뉴를 제공
}

class Baristar {
  makeCoffee = (coffee) => new coffee(); // 커피를 생산
}

class Coffee {}
class Americano extends Coffee {}
class Cappuccino extends Coffee {}
class CaffeLatte extends Coffee {}

const customer = new Customer();
const baristar = new Baristar();
const menuBoard = new MenuBoard();

menuBoard.init([Americano, Cappuccino, CaffeLatte]);
customer.order('Americano', menuBoard, baristar);

호오! 간단하죠? 근데 부족한 것이 있습니다. 바로 객체마다 상태(state)가 없다는 것인데요.
상태가 없어도 동작이 된다. 즉 상태보다는 책임 위주의 설계를 해야한다는 것이 방증이 되네요!

마무리

오늘은 협력, 역할, 책임의 중요성을 살펴보면서 구현을 해보았습니다.
'객체지향의 사실과 오해' 책의 내용의 일부분만 구현했지만, 왜 3가지 관점(협력, 역할, 책임)이 중요한지 전달되었으면 좋겠네요 😊
다음 편에서는 인터페이스와 구현이라는 주제로 나눠보도록 하죠!

profile
도전하고 성장하는 개발자입니다 :)

0개의 댓글