객체 지향 복습
CoffeeStore
학습 목표
• 객체 지향(Object-Oriented) 개발방법에 대해서 복습해서 이해한다.
현재 배워본 것들
• 객체지향
• 메시징(위임)
• 정보은닉(Information Hiding)
• 추상화/다형성
• 상속
• 예외처리
• 컬렉션
컬렉션
• 데이터를 담을 수 있는 객체
컬렉션
데이터1
데이터2
데이터3
컬렉션: 어떤 동작이 필요할까요?
컬렉션
데이터1
데이터2
데이터3
컬렉션
컬렉션
데이터1
데이터2
데이터3
내가 원하는 데이터를 읽는다 라는 행위
컬렉션
컬렉션
데이터1
데이터2데이터3
데이터를 지운다라는 행위
컬렉션에서 기본적으로 필요한 동작
• 데이터를 넣는다.
• 데이터를 읽는다.
• 데이터를 제거한다.
List에서 제공하는 주요 메서드
이름 기능
add(E e) E는 처음에 List를 선언할때 사용했던 타입의 종류(Generic이라고 함)
새로운 객체를 List에 집어넣는 명령
List<String> strList = new ArrayList<String>(); 으로 만들었다면
String str = "User4";
strList.add(str); //String 타입만 가능
contains(Object o) 파라미터로 전달된 객체가 존재하는지 확인해서 true/false로 전달한다.
데이터 개수가 많을수록 contains 는 느려진다.
get(int index) index의 데이터를 돌려준다.
remove(int index) index 위치의 데이터를 삭제한다.
컬렉션은 데이터를 담는 객체 #1
• 우리는 컬렉션에 데이터를 주면, 데이터를 넣으라고 명령한다.
• 우리는 컬렉션에 데이터를 달라고 요구한다.
• 우리는 컬렉션에 데이터를 지우라고 요구한다.
실제로 행동을 하는 주체는 누구인가?
우리는 메시지로 일을 객체에 위임한다.
컬렉션은 데이터를 담는 객체 #2
결국 우리는 객체의 인터페이스만 관심을 둠
(추상화)
내부 구조를 몰라도 되므로, 내부 구조가 바
뀌더라도 문제가 발생하지 않음.
실습 #1
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class ArrayListTest {
public static void main(String...args) {
Collection<User> users = new ArrayList<User>();
update(users);
print(users);
}
public static void update(Collection<User> users) {
users.add(new User("User1"));
users.add(new User("User2"));
}
public static void print(Collection<User> users) {
for (User user : users) {
System.out.println(user.getName());
}
}
}
추상도가 높아질 수록, 사용범위도 넓어진다.
Collection<E>
List<E> Set<E>
ArrayList<E> HashSet<E>
HashSet은 List으로 받을 수 없다.
ArrayList는 Collection으로 받을 수 있다.
ArrayList는 Set으로 받을 수 없다.
HashSet은 Collection으로 받을 수 있다.
실습 프로젝트 - 다 함께 진행해봅시다.
• 커피가게를 생각해봅시다.
• 다음 메뉴판이 있습니다.
• 실습코드는 https://github.com/charsyam/CoffeeStoreExample
메뉴 가격
아메리카노 3000
카페라테 4000
카푸치노 4000
카라멜마키아토 5000
커피가게에서 커피를 주문하는 과정
손님이 커피를 주문
커피가게에서 커피를 주문하는 과정
손님이 커피를 주문
커피가게에서 커피를 주문하는 과정
손님이 커피아메리카노를 주문
커피가게에서 커피를 주문하는 과정
손님이 커피아메리카노를 바리스타에게 주문
커피가게에서 커피를 주문하는 과정
손님이 메뉴판에서 보고
메뉴 커피아메리카노를 바리스타에게 주문
커피가게에서 커피를 주문하는 과정
바리스타가 커피를 제조
커피가게에서 커피를 주문하는 과정
바리스타가 커피를 제조
커피가게에서 커피를 주문하는 과정
바리스타가 커피아메리카노를 제조
커피가게에서 커피를 주문하는 과정
바리스타가 메뉴에 있는
커피아메리카노를 제조
어떤 키워드들이 나왔나요?
커피
메뉴판
손님
바리스타
주문 제조
메뉴
명사와 동사?
커피
메뉴판
손님
바리스타
주문 제조
메뉴
각 단어를 관계별로 묶어봅시다.
커피
메뉴판
손님
바리스타
주문 제조
메뉴
각 단어를 관계별로 묶어봅시다.
커피
메뉴판손님
바리스타
주문 제조메뉴
좀 더 묶어봅시다.
손님은 무엇을 하나요?
손님
손님은 메뉴를 선택합니다.
어디에서 보고?
손님은 메뉴를 주문합니다.
누구에게 주문?
좀 더 묶어봅시다.
바리스타는 무엇을 하나요?
바리스타
커피를 제조해서 줍니다.
커피종류는?
어떤 관계에 있을까요?
손님
바리스타
메뉴판
1. 메뉴를 선택한다.
2. 메뉴의 정보를 돌려준다.
3. 메뉴를 주문한다.(만들어주길 요청)
4. 메뉴를 만들어서 돌려준다.
메뉴?
메뉴는 어디에 속해야 할까요?
메뉴 가격
아메리카노 3000
카페라테 4000
카푸치노 4000
카라멜마키아토 5000
메뉴는 메뉴판 안에 있습니다.
손님
바리스타
메뉴판
1. 메뉴를 선택한다.
2. 메뉴의 정보를 돌려준다.
3. 메뉴를 주문한다.(만들어주길 요청)
4. 메뉴를 만들어서 돌려준다.
메뉴
* 메뉴는 여러 개 일 수 있습니다.
MenuItem 클래스
• 메뉴판이 영어로 Menu 이므로 앞으로 하나의 메뉴를 MenuItem으로 정의
• MenuItem 을 보고 우리는 어떤 정보를 얻을 수 있어야 하나요?
메뉴 가격
아메리카노 3000
카페라테 4000
카푸치노 4000
카라멜마키아토 5000
MenuItem 클래스
MenuItem
메뉴 이름
메뉴 가격
메뉴 이름을 알려준다.
메뉴 가격을 알려준다.
MenuItem 클래스
class MenuItem {
String getName();
int getPrice();
}
Menu 클래스
메뉴판은 어떤 기능이 있어야 할까?
Menu 클래스
Menu
MenuItem
2. MenuItem 을 전달한다. ……
MenuItem
1. 메뉴명을 전달한다.
Menu 클래스
MenuItem 들을 저장하기 위해서는
무엇이 필요할까요?
MenuItem 의 개수를 알고 있나요?
Menu 클래스
Collection
Menu 클래스
class Menu {
MenuItem choose(String name);
}
Coffee 클래스
Coffee 는 어떤 기능이 있어야 할까요?
우리가 직접 마실 수 없으니 일단은 자기의
종류만 알려주도록 합시다.
Coffee 클래스
Coffee
메뉴 이름
메뉴 이름을 알려준다.
Coffee 클래스
class Coffee {
String getName();
}
Barista 클래스
Barista 는 무엇을 해야하나요?
Barista 클래스
Barista메뉴를 전달한다.
메뉴 제조메뉴를 만들어서 돌려준다.
Coffee 클래스 #1
class Barista {
Coffee make(String name);
}
Coffee 클래스 #2
class Barista {
Coffee make(MenuItem menuItem);
}
Barista 클래스
커피 제조를 위해서 메뉴의 이름만 받으면
될까요? MenuItem을 받아야 할까요?
그리고 그 이유는?
Customer 클래스
Customer 는 무엇을 해야하나요?
1. menu를 보고 menuItem을 가지고
2. menuItem으로 Barista에게 커피 제
조를 시킵니다.
Customer 클래스
Customer
주문
메뉴, 바리스타를 전달한다.
Barista
Menu
choose(메뉴이름)
MenuItem
make(menuItem)
Coffee
Customer 클래스
class Customer {
void order(String menuName,
Menu menu,
Barista barista);
}
주문 코드
public class CoffeeStore {
public static void main(String [] args) {
Customer customer = new Customer();
Barista barista = new Barista();
Menu menu = new Menu();
customer.order("Americano", menu, barista);
}
}
코드 작성 : MenuItem
MenuItem class를 작성해 봅시다.
MenuItem 클래스
아래의 코드를 보면 어떤 속성이 필요한가요?
class MenuItem {
String getName();
int getPrice();
}
제공할
메소드
MenuItem 클래스
public class MenuItem {
private String name;
private int price;
public MenuItem(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public int getPrice() { return price; }
}
코드 작성 : Menu
Menu class를 작성해 봅시다.
Menu 클래스
class Menu {
MenuItem choose(String name);
}
MenuItem 이름으로 MenuItem을 찾아서 돌려줘야 합니다.
Menu 클래스 #1
public class Menu {
private List<MenuItem> menus;
public Menu(List<MenuItem> menus) {
this. menus = menus;
}
public MenuItem choose(String name) {
//코드를 구현해봅시다.
}
}
주문 코드
public class CoffeeStore {
public static void main(String [] args) {
Customer customer = new Customer();
Barista barista = new Barista();
List<MenuItem> menus = new ArrayList<MenuItem>();
menus.add(new MenuItem("Americano", 3000));
menus.add(new MenuItem("Caffelatte", 4000));
Menu menu = new Menu(menus);
customer.order("Americano", menu, barista);
}
}
Menu 클래스 #1
public class Menu {
private List<MenuItem> menus;
public Menu(List<MenuItem> menus) {
this. menus = menus;
}
public MenuItem choose(String name) {
//코드를 구현해봅시다.
}
}
Menu 클래스 #2
public class Menu {
……
public MenuItem choose(String name) {
for (MenuItem menuItem : menus) {
if (menuItem.getName().equals(name)) {
return menuItem;
}
}
return null;
}
}
코드 작성 : Coffee
Coffee class를 작성해 봅시다.
Coffee Class
public class Coffee {
private String name;
public Coffee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
코드 작성 : Barista
Barista class를 작성해 봅시다.
Barista Class
public class Barista {
public Coffee make(MenuItem menuItem) {
return new Coffee(menuItem.getName());
}
}
코드 작성 : Customer
Customer class를 작성해 봅시다.
Customer 클래스
class Customer {
void order(String menuName,
Menu menu,
Barista barista);
}
1. menu를 보고 menuItem을 가지고
2. menuItem으로 Barista에게 커피 제조를 시킵니다.
Customer Class
public class Customer {
public void order(String name, Menu menu, Barista barista) {
MenuItem menuItem = menu.choose(name);
Coffee coffee = barista.make(menuItem);
System.out.println("Drink : " + coffee.getName());
}
}
다형성을 통한 코드의 개선
수정할 때 여러 부분이 바뀌어야 하는 건
좋지 않습니다.
주문 코드
public class CoffeeStore {
public static void main(String [] args) {
Customer customer = new Customer();
Barista barista = new Barista();
List<MenuItem> menus = new ArrayList<MenuItem>();
menus.add(new MenuItem("Americano", 3000));
menus.add(new MenuItem("Caffelatte", 4000));
Menu menu = new Menu(menus);
customer.order("Americano", menu, barista);
}
}
현재 코드 Menu의 단점
Menu가 내부적으로 List를 쓰고 있어서
MenuItem이 많아지면 속도가 느려집니다.
정보 은닉(Information Hiding) #1
사용자 Menu
연관된 객체의 상세 정보를 알 수록
수정하기 어렵다. Menu가 다른
컬렉션을 사용하면?
나는 Menu가 List 형태의 menus
를 가지고 있는걸 알고 있어. 그래서
너의 menus.get을 바로 호출할께.
정보 은닉(Information Hiding) #2
사용자 Menu
연관된 객체의 정보를 모를 수록
상대방이 바뀌어도 수정이 필요 없다.
나는 너에 대해서는 전혀 모르고
choose로 이름을 주면 MenuItem
을 주는것만 알아.
Menu를 인터페이스로 바꾸자.
public interface Menu {
public MenuItem choose(String name);
}
ListTypeMenu Class
import java.util.List;
public class ListTypeMenu implements Menu {
private List<MenuItem> menus;
public ListTypeMenu(List<MenuItem> menus) {
this.menus = menus;
}
public MenuItem choose(String name) {
for (MenuItem menuItem : menus) {
if (menuItem.getName().equals(name)) {
return menuItem;
}
}
return null;
}
}
MapTypeMenu Class
import java.util.HashMap;
import java.util.Collection;
public class MapTypeMenu implements Menu {
private HashMap<String, MenuItem> menus = new HashMap<>();
public MapTypeMenu(Collection<MenuItem> menuItems) {
for (MenuItem menuItem : menuItems) {
menus.put(menuItem.getName(), menuItem);
}
}
public MenuItem choose(String name) {
return menus.get(name);
}
}
주문 코드 : ListTypeMenu
public class CoffeeStore {
public static void main(String [] args) {
Customer customer = new Customer();
Barista barista = new Barista();
List<MenuItem> menus = new ArrayList<MenuItem>();
menus.add(new MenuItem("Americano", 3000));
menus.add(new MenuItem("Caffelatte", 4000));
Menu menu = new ListTypeMenu(menus);
customer.order("Americano", menu, barista);
}
}
주문 코드 : MapTypeMenu
public class CoffeeStore {
public static void main(String [] args) {
Customer customer = new Customer();
Barista barista = new Barista();
List<MenuItem> menus = new ArrayList<MenuItem>();
menus.add(new MenuItem("Americano", 3000));
menus.add(new MenuItem("Caffelatte", 4000));
Menu menu = new MapTypeMenu(menus);
customer.order("Americano", menu, barista);
}
}
예외처리
정상적인 상황에서 코드는 잘 돌아갑니다.
(보통은…)
커피 주문에서 문제가 될 수 있는 상황은?
커피 주문에서 문제가 될 수 있는 상황은?
손님이 메뉴판을 보고 메뉴를 고릅니다.
메뉴판에 없는 메뉴 이름이면?
바리스타가 메뉴를 받아서 제조합니다.
바리스타가 못 만드는 메뉴면?
Customer Class
public class Customer {
public void order(String name, Menu menu, Barista barista) {
MenuItem menuItem = menu.choose(name);
Coffee coffee = barista.make(menuItem);
System.out.println("Drink : " + coffee.getName());
}
}
없는 메뉴라면
menuItem 은 null 이다.
barista가 못만들면
coffee가 null 이다.
NullPointerException 발생
NullPointerException
public class Customer {
public void order(String name, Menu menu, Barista barista) {
try {
MenuItem menuItem = menu.choose(name);
Coffee coffee = barista.make(menuItem);
System.out.println("Drink : " + coffee.getName());
} catch(NullPointerException e) {
System.out.println("Can’t Drink : " + name);
}
}
}
주문 코드 : NullPointerException
public class CoffeeStore {
public static void main(String [] args) {
Customer customer = new Customer();
Barista barista = new Barista();
List<MenuItem> menus = new ArrayList<MenuItem>();
menus.add(new MenuItem("Americano", 3000));
menus.add(new MenuItem("Caffelatte", 4000));
Menu menu = new MapTypeMenu(menus);
customer.order("milk", menu, barista);
}
}
예외를 구분하고 싶다면 : 서로 다른 에러
손님이 메뉴판을 보고 메뉴를 고릅니다.
메뉴판에 없는 메뉴 이름이면?
바리스타가 메뉴를 받아서 제조합니다.
바리스타가 못 만드는 메뉴면?
NotExistedMenuException
NotSupportedMenuException
NotExistedMenuException
class NotExistedMenuException extends Exception {
public NotExistedMenuException(String menuName) {
super("NotExistedMenuException : " + menuName);
}
}
NotSupportedMenuException
class NotSupportedMenuException extends Exception {
public NotSupportedMenuException(String menuName) {
super("NotSupportedMenuException : " + menuName);
}
}
Menu interface 수정
public interface Menu {
public MenuItem choose(String name) throws NotExistedMenuException;
}
ListTypeMenu Class 수정
import java.util.List;
public class ListTypeMenu implements Menu {
private List<MenuItem> menus;
public ListTypeMenu(List<MenuItem> menus) {
this.menus = menus;
}
public MenuItem choose(String name) throws NotExistedMenuException {
for (MenuItem menuItem : menus) {
if (menuItem.getName().equals(name)) {
return menuItem;
}
}
throw new NotExistedMenuException(name);
}
}
MapTypeMenu Class 수정
import java.util.HashMap;
import java.util.Collection;
public class MapTypeMenu implements Menu {
private HashMap<String, MenuItem> menus = new HashMap<>();
public MapTypeMenu(Collection<MenuItem> menuItems) {
for (MenuItem menuItem : menuItems) {
menus.put(menuItem.getName(), menuItem);
}
}
public MenuItem choose(String name) throws NotExistedMenuException {
if (menus.containsKey(name) == false) {
throw new NotExistedMenuException(name);
}
return menus.get(name);
}
}
Barista Class의 변경
public class Barista {
public Coffee make(MenuItem menuItem) throws NotSupportedMenuException {
return new Coffee(menuItem.getName());
}
}
NewbieBarista 를 만들자
아메리카노 이외에는 만들지 못하는 초보
그러나 다른 부분은 Barista를 그대로 상속
NewbieBarista Class
public class NewbieBarista extends Barista {
public Coffee make(MenuItem menuItem) throws NotSupportedMenuException {
if (menuItem.getName().equals("americano") == false) {
throw new NotSupportedMenuException(menuItem.getName());
}
return new Coffee(menuItem.getName());
}
}
NewbieBarista Class
public class NewbieBarista extends Barista {
public Coffee make(MenuItem menuItem) throws NotSupportedMenuException {
if (menuItem.getName().equals("americano") == false) {
throw new NotSupportedMenuException(menuItem.getName());
}
return new Coffee(menuItem.getName());
}
}
Overriding : 부모 클래스의 메서드를 재정의
주문 코드 비교 : Barista
import java.util.ArrayList;
import java.util.List;
public class CoffeeStore {
public static void main(String[] args) {
Customer customer = new Customer();
Barista brista = new Barista();
List<MenuItem> coffeeMenu = new ArrayList<MenuItem>();
coffeeMenu.add(new MenuItem("americano", 3000));
coffeeMenu.add(new MenuItem("caffelatte", 4000));
coffeeMenu.add(new MenuItem("cafuchino", 4000));
Menu menu = new MapTypeMenu(coffeeMenu);
customer.order("milk", menu, brista);
customer.order("caffelatte", menu, brista);
}
}
주문 코드 비교 : NewbieBarista
import java.util.ArrayList;
import java.util.List;
public class CoffeeStore {
public static void main(String[] args) {
Customer customer = new Customer();
Barista brista = new NewbieBarista();
List<MenuItem> coffeeMenu = new ArrayList<MenuItem>();
coffeeMenu.add(new MenuItem("americano", 3000));
coffeeMenu.add(new MenuItem("caffelatte", 4000));
coffeeMenu.add(new MenuItem("cafuchino", 4000));
Menu menu = new MapTypeMenu(coffeeMenu);
customer.order("milk", menu, brista);
customer.order("caffelatte", menu, brista);
}
}
Reference
• 객체지향의 사실과 오해(조영호, 위키북스)
• 생각하라, 객체지향처럼(김승영, 우아한형제들 기술블로그)
• http://woowabros.github.io/study/2016/07/07/think_object_oriented.html

Coffee store

  • 1.
  • 2.
    학습 목표 • 객체지향(Object-Oriented) 개발방법에 대해서 복습해서 이해한다.
  • 3.
    현재 배워본 것들 •객체지향 • 메시징(위임) • 정보은닉(Information Hiding) • 추상화/다형성 • 상속 • 예외처리 • 컬렉션
  • 4.
    컬렉션 • 데이터를 담을수 있는 객체 컬렉션 데이터1 데이터2 데이터3
  • 5.
    컬렉션: 어떤 동작이필요할까요? 컬렉션 데이터1 데이터2 데이터3
  • 6.
  • 7.
  • 8.
    컬렉션에서 기본적으로 필요한동작 • 데이터를 넣는다. • 데이터를 읽는다. • 데이터를 제거한다.
  • 9.
    List에서 제공하는 주요메서드 이름 기능 add(E e) E는 처음에 List를 선언할때 사용했던 타입의 종류(Generic이라고 함) 새로운 객체를 List에 집어넣는 명령 List<String> strList = new ArrayList<String>(); 으로 만들었다면 String str = "User4"; strList.add(str); //String 타입만 가능 contains(Object o) 파라미터로 전달된 객체가 존재하는지 확인해서 true/false로 전달한다. 데이터 개수가 많을수록 contains 는 느려진다. get(int index) index의 데이터를 돌려준다. remove(int index) index 위치의 데이터를 삭제한다.
  • 10.
    컬렉션은 데이터를 담는객체 #1 • 우리는 컬렉션에 데이터를 주면, 데이터를 넣으라고 명령한다. • 우리는 컬렉션에 데이터를 달라고 요구한다. • 우리는 컬렉션에 데이터를 지우라고 요구한다. 실제로 행동을 하는 주체는 누구인가? 우리는 메시지로 일을 객체에 위임한다.
  • 11.
    컬렉션은 데이터를 담는객체 #2 결국 우리는 객체의 인터페이스만 관심을 둠 (추상화) 내부 구조를 몰라도 되므로, 내부 구조가 바 뀌더라도 문제가 발생하지 않음.
  • 12.
    실습 #1 import java.util.Collection; importjava.util.List; import java.util.ArrayList; import java.util.LinkedList; class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } } public class ArrayListTest { public static void main(String...args) { Collection<User> users = new ArrayList<User>(); update(users); print(users); } public static void update(Collection<User> users) { users.add(new User("User1")); users.add(new User("User2")); } public static void print(Collection<User> users) { for (User user : users) { System.out.println(user.getName()); } } }
  • 13.
    추상도가 높아질 수록,사용범위도 넓어진다. Collection<E> List<E> Set<E> ArrayList<E> HashSet<E> HashSet은 List으로 받을 수 없다. ArrayList는 Collection으로 받을 수 있다. ArrayList는 Set으로 받을 수 없다. HashSet은 Collection으로 받을 수 있다.
  • 14.
    실습 프로젝트 -다 함께 진행해봅시다. • 커피가게를 생각해봅시다. • 다음 메뉴판이 있습니다. • 실습코드는 https://github.com/charsyam/CoffeeStoreExample 메뉴 가격 아메리카노 3000 카페라테 4000 카푸치노 4000 카라멜마키아토 5000
  • 15.
    커피가게에서 커피를 주문하는과정 손님이 커피를 주문
  • 16.
    커피가게에서 커피를 주문하는과정 손님이 커피를 주문
  • 17.
    커피가게에서 커피를 주문하는과정 손님이 커피아메리카노를 주문
  • 18.
    커피가게에서 커피를 주문하는과정 손님이 커피아메리카노를 바리스타에게 주문
  • 19.
    커피가게에서 커피를 주문하는과정 손님이 메뉴판에서 보고 메뉴 커피아메리카노를 바리스타에게 주문
  • 20.
    커피가게에서 커피를 주문하는과정 바리스타가 커피를 제조
  • 21.
    커피가게에서 커피를 주문하는과정 바리스타가 커피를 제조
  • 22.
    커피가게에서 커피를 주문하는과정 바리스타가 커피아메리카노를 제조
  • 23.
    커피가게에서 커피를 주문하는과정 바리스타가 메뉴에 있는 커피아메리카노를 제조
  • 24.
  • 25.
  • 26.
    각 단어를 관계별로묶어봅시다. 커피 메뉴판 손님 바리스타 주문 제조 메뉴
  • 27.
    각 단어를 관계별로묶어봅시다. 커피 메뉴판손님 바리스타 주문 제조메뉴
  • 28.
  • 29.
    손님 손님은 메뉴를 선택합니다. 어디에서보고? 손님은 메뉴를 주문합니다. 누구에게 주문?
  • 30.
  • 31.
  • 32.
    어떤 관계에 있을까요? 손님 바리스타 메뉴판 1.메뉴를 선택한다. 2. 메뉴의 정보를 돌려준다. 3. 메뉴를 주문한다.(만들어주길 요청) 4. 메뉴를 만들어서 돌려준다.
  • 33.
    메뉴? 메뉴는 어디에 속해야할까요? 메뉴 가격 아메리카노 3000 카페라테 4000 카푸치노 4000 카라멜마키아토 5000
  • 34.
    메뉴는 메뉴판 안에있습니다. 손님 바리스타 메뉴판 1. 메뉴를 선택한다. 2. 메뉴의 정보를 돌려준다. 3. 메뉴를 주문한다.(만들어주길 요청) 4. 메뉴를 만들어서 돌려준다. 메뉴 * 메뉴는 여러 개 일 수 있습니다.
  • 35.
    MenuItem 클래스 • 메뉴판이영어로 Menu 이므로 앞으로 하나의 메뉴를 MenuItem으로 정의 • MenuItem 을 보고 우리는 어떤 정보를 얻을 수 있어야 하나요? 메뉴 가격 아메리카노 3000 카페라테 4000 카푸치노 4000 카라멜마키아토 5000
  • 36.
    MenuItem 클래스 MenuItem 메뉴 이름 메뉴가격 메뉴 이름을 알려준다. 메뉴 가격을 알려준다.
  • 37.
    MenuItem 클래스 class MenuItem{ String getName(); int getPrice(); }
  • 38.
    Menu 클래스 메뉴판은 어떤기능이 있어야 할까?
  • 39.
    Menu 클래스 Menu MenuItem 2. MenuItem을 전달한다. …… MenuItem 1. 메뉴명을 전달한다.
  • 40.
    Menu 클래스 MenuItem 들을저장하기 위해서는 무엇이 필요할까요? MenuItem 의 개수를 알고 있나요?
  • 41.
  • 42.
    Menu 클래스 class Menu{ MenuItem choose(String name); }
  • 43.
    Coffee 클래스 Coffee 는어떤 기능이 있어야 할까요? 우리가 직접 마실 수 없으니 일단은 자기의 종류만 알려주도록 합시다.
  • 44.
  • 45.
    Coffee 클래스 class Coffee{ String getName(); }
  • 46.
    Barista 클래스 Barista 는무엇을 해야하나요?
  • 47.
    Barista 클래스 Barista메뉴를 전달한다. 메뉴제조메뉴를 만들어서 돌려준다.
  • 48.
    Coffee 클래스 #1 classBarista { Coffee make(String name); }
  • 49.
    Coffee 클래스 #2 classBarista { Coffee make(MenuItem menuItem); }
  • 50.
    Barista 클래스 커피 제조를위해서 메뉴의 이름만 받으면 될까요? MenuItem을 받아야 할까요? 그리고 그 이유는?
  • 51.
    Customer 클래스 Customer 는무엇을 해야하나요? 1. menu를 보고 menuItem을 가지고 2. menuItem으로 Barista에게 커피 제 조를 시킵니다.
  • 52.
    Customer 클래스 Customer 주문 메뉴, 바리스타를전달한다. Barista Menu choose(메뉴이름) MenuItem make(menuItem) Coffee
  • 53.
    Customer 클래스 class Customer{ void order(String menuName, Menu menu, Barista barista); }
  • 54.
    주문 코드 public classCoffeeStore { public static void main(String [] args) { Customer customer = new Customer(); Barista barista = new Barista(); Menu menu = new Menu(); customer.order("Americano", menu, barista); } }
  • 55.
    코드 작성 :MenuItem MenuItem class를 작성해 봅시다.
  • 56.
    MenuItem 클래스 아래의 코드를보면 어떤 속성이 필요한가요? class MenuItem { String getName(); int getPrice(); } 제공할 메소드
  • 57.
    MenuItem 클래스 public classMenuItem { private String name; private int price; public MenuItem(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } }
  • 58.
    코드 작성 :Menu Menu class를 작성해 봅시다.
  • 59.
    Menu 클래스 class Menu{ MenuItem choose(String name); } MenuItem 이름으로 MenuItem을 찾아서 돌려줘야 합니다.
  • 60.
    Menu 클래스 #1 publicclass Menu { private List<MenuItem> menus; public Menu(List<MenuItem> menus) { this. menus = menus; } public MenuItem choose(String name) { //코드를 구현해봅시다. } }
  • 61.
    주문 코드 public classCoffeeStore { public static void main(String [] args) { Customer customer = new Customer(); Barista barista = new Barista(); List<MenuItem> menus = new ArrayList<MenuItem>(); menus.add(new MenuItem("Americano", 3000)); menus.add(new MenuItem("Caffelatte", 4000)); Menu menu = new Menu(menus); customer.order("Americano", menu, barista); } }
  • 62.
    Menu 클래스 #1 publicclass Menu { private List<MenuItem> menus; public Menu(List<MenuItem> menus) { this. menus = menus; } public MenuItem choose(String name) { //코드를 구현해봅시다. } }
  • 63.
    Menu 클래스 #2 publicclass Menu { …… public MenuItem choose(String name) { for (MenuItem menuItem : menus) { if (menuItem.getName().equals(name)) { return menuItem; } } return null; } }
  • 64.
    코드 작성 :Coffee Coffee class를 작성해 봅시다.
  • 65.
    Coffee Class public classCoffee { private String name; public Coffee(String name) { this.name = name; } public String getName() { return name; } }
  • 66.
    코드 작성 :Barista Barista class를 작성해 봅시다.
  • 67.
    Barista Class public classBarista { public Coffee make(MenuItem menuItem) { return new Coffee(menuItem.getName()); } }
  • 68.
    코드 작성 :Customer Customer class를 작성해 봅시다.
  • 69.
    Customer 클래스 class Customer{ void order(String menuName, Menu menu, Barista barista); } 1. menu를 보고 menuItem을 가지고 2. menuItem으로 Barista에게 커피 제조를 시킵니다.
  • 70.
    Customer Class public classCustomer { public void order(String name, Menu menu, Barista barista) { MenuItem menuItem = menu.choose(name); Coffee coffee = barista.make(menuItem); System.out.println("Drink : " + coffee.getName()); } }
  • 71.
    다형성을 통한 코드의개선 수정할 때 여러 부분이 바뀌어야 하는 건 좋지 않습니다.
  • 72.
    주문 코드 public classCoffeeStore { public static void main(String [] args) { Customer customer = new Customer(); Barista barista = new Barista(); List<MenuItem> menus = new ArrayList<MenuItem>(); menus.add(new MenuItem("Americano", 3000)); menus.add(new MenuItem("Caffelatte", 4000)); Menu menu = new Menu(menus); customer.order("Americano", menu, barista); } }
  • 73.
    현재 코드 Menu의단점 Menu가 내부적으로 List를 쓰고 있어서 MenuItem이 많아지면 속도가 느려집니다.
  • 74.
    정보 은닉(Information Hiding)#1 사용자 Menu 연관된 객체의 상세 정보를 알 수록 수정하기 어렵다. Menu가 다른 컬렉션을 사용하면? 나는 Menu가 List 형태의 menus 를 가지고 있는걸 알고 있어. 그래서 너의 menus.get을 바로 호출할께.
  • 75.
    정보 은닉(Information Hiding)#2 사용자 Menu 연관된 객체의 정보를 모를 수록 상대방이 바뀌어도 수정이 필요 없다. 나는 너에 대해서는 전혀 모르고 choose로 이름을 주면 MenuItem 을 주는것만 알아.
  • 76.
    Menu를 인터페이스로 바꾸자. publicinterface Menu { public MenuItem choose(String name); }
  • 77.
    ListTypeMenu Class import java.util.List; publicclass ListTypeMenu implements Menu { private List<MenuItem> menus; public ListTypeMenu(List<MenuItem> menus) { this.menus = menus; } public MenuItem choose(String name) { for (MenuItem menuItem : menus) { if (menuItem.getName().equals(name)) { return menuItem; } } return null; } }
  • 78.
    MapTypeMenu Class import java.util.HashMap; importjava.util.Collection; public class MapTypeMenu implements Menu { private HashMap<String, MenuItem> menus = new HashMap<>(); public MapTypeMenu(Collection<MenuItem> menuItems) { for (MenuItem menuItem : menuItems) { menus.put(menuItem.getName(), menuItem); } } public MenuItem choose(String name) { return menus.get(name); } }
  • 79.
    주문 코드 :ListTypeMenu public class CoffeeStore { public static void main(String [] args) { Customer customer = new Customer(); Barista barista = new Barista(); List<MenuItem> menus = new ArrayList<MenuItem>(); menus.add(new MenuItem("Americano", 3000)); menus.add(new MenuItem("Caffelatte", 4000)); Menu menu = new ListTypeMenu(menus); customer.order("Americano", menu, barista); } }
  • 80.
    주문 코드 :MapTypeMenu public class CoffeeStore { public static void main(String [] args) { Customer customer = new Customer(); Barista barista = new Barista(); List<MenuItem> menus = new ArrayList<MenuItem>(); menus.add(new MenuItem("Americano", 3000)); menus.add(new MenuItem("Caffelatte", 4000)); Menu menu = new MapTypeMenu(menus); customer.order("Americano", menu, barista); } }
  • 81.
    예외처리 정상적인 상황에서 코드는잘 돌아갑니다. (보통은…)
  • 82.
    커피 주문에서 문제가될 수 있는 상황은?
  • 83.
    커피 주문에서 문제가될 수 있는 상황은? 손님이 메뉴판을 보고 메뉴를 고릅니다. 메뉴판에 없는 메뉴 이름이면? 바리스타가 메뉴를 받아서 제조합니다. 바리스타가 못 만드는 메뉴면?
  • 84.
    Customer Class public classCustomer { public void order(String name, Menu menu, Barista barista) { MenuItem menuItem = menu.choose(name); Coffee coffee = barista.make(menuItem); System.out.println("Drink : " + coffee.getName()); } } 없는 메뉴라면 menuItem 은 null 이다. barista가 못만들면 coffee가 null 이다. NullPointerException 발생
  • 85.
    NullPointerException public class Customer{ public void order(String name, Menu menu, Barista barista) { try { MenuItem menuItem = menu.choose(name); Coffee coffee = barista.make(menuItem); System.out.println("Drink : " + coffee.getName()); } catch(NullPointerException e) { System.out.println("Can’t Drink : " + name); } } }
  • 86.
    주문 코드 :NullPointerException public class CoffeeStore { public static void main(String [] args) { Customer customer = new Customer(); Barista barista = new Barista(); List<MenuItem> menus = new ArrayList<MenuItem>(); menus.add(new MenuItem("Americano", 3000)); menus.add(new MenuItem("Caffelatte", 4000)); Menu menu = new MapTypeMenu(menus); customer.order("milk", menu, barista); } }
  • 87.
    예외를 구분하고 싶다면: 서로 다른 에러 손님이 메뉴판을 보고 메뉴를 고릅니다. 메뉴판에 없는 메뉴 이름이면? 바리스타가 메뉴를 받아서 제조합니다. 바리스타가 못 만드는 메뉴면? NotExistedMenuException NotSupportedMenuException
  • 88.
    NotExistedMenuException class NotExistedMenuException extendsException { public NotExistedMenuException(String menuName) { super("NotExistedMenuException : " + menuName); } }
  • 89.
    NotSupportedMenuException class NotSupportedMenuException extendsException { public NotSupportedMenuException(String menuName) { super("NotSupportedMenuException : " + menuName); } }
  • 90.
    Menu interface 수정 publicinterface Menu { public MenuItem choose(String name) throws NotExistedMenuException; }
  • 91.
    ListTypeMenu Class 수정 importjava.util.List; public class ListTypeMenu implements Menu { private List<MenuItem> menus; public ListTypeMenu(List<MenuItem> menus) { this.menus = menus; } public MenuItem choose(String name) throws NotExistedMenuException { for (MenuItem menuItem : menus) { if (menuItem.getName().equals(name)) { return menuItem; } } throw new NotExistedMenuException(name); } }
  • 92.
    MapTypeMenu Class 수정 importjava.util.HashMap; import java.util.Collection; public class MapTypeMenu implements Menu { private HashMap<String, MenuItem> menus = new HashMap<>(); public MapTypeMenu(Collection<MenuItem> menuItems) { for (MenuItem menuItem : menuItems) { menus.put(menuItem.getName(), menuItem); } } public MenuItem choose(String name) throws NotExistedMenuException { if (menus.containsKey(name) == false) { throw new NotExistedMenuException(name); } return menus.get(name); } }
  • 93.
    Barista Class의 변경 publicclass Barista { public Coffee make(MenuItem menuItem) throws NotSupportedMenuException { return new Coffee(menuItem.getName()); } }
  • 94.
    NewbieBarista 를 만들자 아메리카노이외에는 만들지 못하는 초보 그러나 다른 부분은 Barista를 그대로 상속
  • 95.
    NewbieBarista Class public classNewbieBarista extends Barista { public Coffee make(MenuItem menuItem) throws NotSupportedMenuException { if (menuItem.getName().equals("americano") == false) { throw new NotSupportedMenuException(menuItem.getName()); } return new Coffee(menuItem.getName()); } }
  • 96.
    NewbieBarista Class public classNewbieBarista extends Barista { public Coffee make(MenuItem menuItem) throws NotSupportedMenuException { if (menuItem.getName().equals("americano") == false) { throw new NotSupportedMenuException(menuItem.getName()); } return new Coffee(menuItem.getName()); } } Overriding : 부모 클래스의 메서드를 재정의
  • 97.
    주문 코드 비교: Barista import java.util.ArrayList; import java.util.List; public class CoffeeStore { public static void main(String[] args) { Customer customer = new Customer(); Barista brista = new Barista(); List<MenuItem> coffeeMenu = new ArrayList<MenuItem>(); coffeeMenu.add(new MenuItem("americano", 3000)); coffeeMenu.add(new MenuItem("caffelatte", 4000)); coffeeMenu.add(new MenuItem("cafuchino", 4000)); Menu menu = new MapTypeMenu(coffeeMenu); customer.order("milk", menu, brista); customer.order("caffelatte", menu, brista); } }
  • 98.
    주문 코드 비교: NewbieBarista import java.util.ArrayList; import java.util.List; public class CoffeeStore { public static void main(String[] args) { Customer customer = new Customer(); Barista brista = new NewbieBarista(); List<MenuItem> coffeeMenu = new ArrayList<MenuItem>(); coffeeMenu.add(new MenuItem("americano", 3000)); coffeeMenu.add(new MenuItem("caffelatte", 4000)); coffeeMenu.add(new MenuItem("cafuchino", 4000)); Menu menu = new MapTypeMenu(coffeeMenu); customer.order("milk", menu, brista); customer.order("caffelatte", menu, brista); } }
  • 99.
    Reference • 객체지향의 사실과오해(조영호, 위키북스) • 생각하라, 객체지향처럼(김승영, 우아한형제들 기술블로그) • http://woowabros.github.io/study/2016/07/07/think_object_oriented.html