커피 자판기 프로그래밍 하기 (OOP 이해하기)

2022. 12. 7. 22:52Trip to Python

파이썬을 공부하면서 두 번째 난관이 찾아왔는데 바로 OOP이다. 시간이 지나고 나니까 미리 만들어 놓은 것을 잘 끌어다쓴다로 귀결되었지만 그 실제 활용에 대해서는 아직도 머리 속에서 개념 정립이 덜 된 것 같다. 커피 자판기 프로그래밍을 다시금 정리하면서 개념을 세워보고자 한다.

 

1. 먼저 필요한 모듈들을 가져온다.

from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

- from 파일명 import 클래스명으로 불러온다. 이를 통해서 클래스 안의 속성과 메소드들을 활용할 수 있다.

 

2. 커피머신 도큐먼트 확인

-  되돌아보면 문서를 제대로 읽지 않고 하다보니 어떻게 할지 막막했던 것 같다. 그 것도 그렇고 문서를 읽어서 어떻게 도움된다는 건지 잘 와닿지 않았는데 설명을 듣고 나니 이해가 되었다.

 

2-1 Menuitem Class

Attributes:

 

* name
(str) The name of the drink.
e.g. “latte”

* cost
(float) The price of the drink.
e.g 1.5

* ingredients
(dictionary) The ingredients and amounts required to make the drink.
e.g. {“water”: 100, “coffee”: 16}

 

2-2 Menu Class
Methods:

* get_items()
Returns all the names of the available menu items as a concatenated string.
e.g. “latte/espresso/cappuccino”

* find_drink(order_name)
Parameter order_name: (str) The name of the drinks order.
Searches the menu for a particular drink by name. Returns a MenuItem object if it exists, otherwise returns None.

 

2-3 CoffeeMaker Class
Methods:


* report()
Prints a report of all resources.
e.g.
Water: 300ml
Milk: 200ml
Coffee: 100g

* is_resource_sufficient(drink)
Parameter drink: (MenuItem) The MenuItem object to make.
Returns True when the drink order can be made, False if ingredients are insufficient.
e.g.
True

* make_coffee(order)
Parameter order: (MenuItem) The MenuItem object to make.
Deducts the required ingredients from the resources.

2-4 MoneyMachine Class
Methods:

* report()
Prints the current profit
e.g.
Money: $0

* make_payment(cost)
Parameter cost: (float) The cost of the drink.
Returns True when payment is accepted, or False if insufficient.
e.g. False

 

3. 프로그래밍 조건 사항을 파악

1) Print report.

2) Check resources sufficient?

3) Process coins.

4) Check transaction successful?

5) Make Coffee.

 

4. menu.py 확인

class MenuItem:
    """Models each Menu Item."""
    def __init__(self, name, water, milk, coffee, cost):
        self.name = name
        self.cost = cost
        self.ingredients = {
            "water": water,
            "milk": milk,
            "coffee": coffee
        }

- 메뉴에 따른 이름과 가격 그리고 재료값을 부여

class Menu:
    """Models the Menu with drinks."""
    def __init__(self):
        self.menu = [
            MenuItem(name="latte", water=200, milk=150, coffee=24, cost=2.5),
            MenuItem(name="espresso", water=50, milk=0, coffee=18, cost=1.5),
            MenuItem(name="cappuccino", water=250, milk=50, coffee=24, cost=3),
        ]

    def get_items(self):
        """Returns all the names of the available menu items"""
        options = ""
        for item in self.menu:
            options += f"{item.name}/"
        return options

    def find_drink(self, order_name):
        """Searches the menu for a particular drink by name. Returns that item if it exists, otherwise returns None"""
        for item in self.menu:
            if item.name == order_name:
                return item
        print("Sorry that item is not available.")

- 메뉴에 속성 값을 부여하고 가능한 메뉴를 불러오고 사용자가 주문한 메뉴가 존재하면 해당 값을 전달

 

5. money_machine.py 확인

class MoneyMachine:

    CURRENCY = "$"

    COIN_VALUES = {
        "quarters": 0.25,
        "dimes": 0.10,
        "nickles": 0.05,
        "pennies": 0.01
    }

    def __init__(self):
        self.profit = 0
        self.money_received = 0

    def report(self):
        """Prints the current profit"""
        print(f"Money: {self.CURRENCY}{self.profit}")

    def process_coins(self):
        """Returns the total calculated from coins inserted."""
        print("Please insert coins.")
        for coin in self.COIN_VALUES:
            self.money_received += int(input(f"How many {coin}?: ")) * self.COIN_VALUES[coin]
        return self.money_received

    def make_payment(self, cost):
        """Returns True when payment is accepted, or False if insufficient."""
        self.process_coins()
        if self.money_received >= cost:
            change = round(self.money_received - cost, 2)
            print(f"Here is {self.CURRENCY}{change} in change.")
            self.profit += cost
            self.money_received = 0
            return True
        else:
            print("Sorry that's not enough money. Money refunded.")
            self.money_received = 0
            return False

- 결제 처리 및 결제 가능 여부 확인

 

6. coffee_maker.py 확인

class CoffeeMaker:
    """Models the machine that makes the coffee"""
    def __init__(self):
        self.resources = {
            "water": 300,
            "milk": 200,
            "coffee": 100,
        }

    def report(self):
        """Prints a report of all resources."""
        print(f"Water: {self.resources['water']}ml")
        print(f"Milk: {self.resources['milk']}ml")
        print(f"Coffee: {self.resources['coffee']}g")

    def is_resource_sufficient(self, drink):
        """Returns True when order can be made, False if ingredients are insufficient."""
        can_make = True
        for item in drink.ingredients:
            if drink.ingredients[item] > self.resources[item]:
                print(f"Sorry there is not enough {item}.")
                can_make = False
        return can_make

    def make_coffee(self, order):
        """Deducts the required ingredients from the resources."""
        for item in order.ingredients:
            self.resources[item] -= order.ingredients[item]
        print(f"Here is your {order.name} ☕️. Enjoy!")

- 해당 메뉴의 소비값과 원재료 량을 확인 후 제조 가능 여부 판단 후 연산

 

7. 각 클래스를 통해 객체 변수 지정

 

from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

money_machine = MoneyMachine()
coffee_maker = CoffeeMaker()
menu = Menu()

 

8. 반복적으로 주문을 받으므로 while 구문을 통한 loop 설정

 

from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

money_machine = MoneyMachine()
coffee_maker = CoffeeMaker()
menu = Menu()

is_on = True

while is_on:

 

9. 메뉴를 받는 문구 출력 설정

 

from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

money_machine = MoneyMachine()
coffee_maker = CoffeeMaker()
menu = Menu()

is_on = True

while is_on:
    options = menu.get_items()
    choice = input(f"What would like? ({options}): ")

- menu.get_items()를 통해 메뉴 str을 가져오고 options라는 변수에 저장. input을 통해 해당 옵션이 담긴 문구를 출력하고 사용자의 입력 값을 choice라는 변수로 받음.

 

10. 특수 기능 report, off 구현

 

from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

money_machine = MoneyMachine()
coffee_maker = CoffeeMaker()
menu = Menu()

is_on = True

while is_on:
    options = menu.get_items()
    choice = input(f"What would like? ({options}): ")
    if choice == "off":
        in_on = False
    elif choice == "report":
        coffee_maker.report()
        money_machine.report()

 

- 각 클래스의 report 메소드를 통해서 해당 속성 값 출력. off의 경우 False를 주어 loop 종료

 

11. 메뉴값과 사용자 입력값 동일 확인, 원재료 양 충분한지 확인, 결제 가능 여부 확인 및 진행, 커피 제조

 

from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

money_machine = MoneyMachine()
coffee_maker = CoffeeMaker()
menu = Menu()

is_on = True

while is_on:
    options = menu.get_items()
    choice = input(f"What would like? ({options}): ")
    if choice == "off":
        in_on = False
    elif choice == "report":
        coffee_maker.report()
        money_machine.report()
    else:
      	drink = menu.find_drink(choice)
        if coffee_maker.is_resource_sufficient(drink):
            if money_machine.make_payment(drink.cost):
                coffee_maker.make_coffee(drink)

- 각 객체에서 메소드를 불러오고 필요한 인자를 잘 확인하는 것이 중요.