0. 기존 코드
class GrabStore:
def __init__(self):
self.money = 0
self.name = "그랩마켓"
self.products = {
1: {"name": "키보드", "price": 30000},
2: {"name": "모니터", "price": 50000},
}
def set_money(self, money):
self.money = money
def set_products(self, products):
self.products = products
def get_money(self):
return self.money
def get_products(self):
return self.products
class User:
def __init__(self):
self.money = 0
self.store = GrabStore()
self.belongs = []
def set_money(self, money):
self.money = money
def set_belongs(self, belongs):
self.belongs = belongs
def get_money(self):
return self.money
def get_belongs(self):
return self.belongs
def get_store(self):
return self.store
def see_product(self, product_id):
products = self.store.get_products()
return products[product_id]
def purchase_product(self, product_id):
product = self.see_product(product_id)
if self.money >= product["price"]:
self.store.products.pop(product_id)
self.money -= product["price"]
self.store.money += product["price"]
self.belongs.append(product)
return product
else:
raise Exception("잔돈이 부족합니다")
if __name__ == "__main__":
user = User()
user.set_money(100000)
user.purchase_product(product_id=1)
문제 1. 다른 Store가 온다면?
문제 1. 다른 Store가 온다면?
1) Store 추상화
2) User에 Store 의존성 주입
from abc import ABC, abstractmethod
class Store(ABC):
@abstractmethod
def __init__(self):
self.money = 0
self.name = ""
self.products = {}
@abstractmethod
def set_money(self, money):
pass
@abstractmethod
def set_products(self, products):
self.products = products
@abstractmethod
def get_money(self):
return self.money
@abstractmethod
def get_products(self):
return self.products
class GrabStore(Store):
def __init__(self):
self.money = 0
self.name = "그랩마켓"
self.products = {
1: {"name": "키보드", "price": 30000},
2: {"name": "모니터", "price": 50000},
}
def set_money(self, money):
self.money = money
def set_products(self, products):
self.products = products
def get_money(self):
return self.money
def get_products(self):
return self.products
class FruitsStore(Store):
def __init__(self):
self.money = 0
self.name = "과일마켓"
self.products = {
1: {"name": "바나나", "price": 30000},
2: {"name": "사과", "price": 50000},
}
def set_money(self, money):
self.money = money
def set_products(self, products):
self.products = products
def get_money(self):
return self.money
def get_products(self):
return self.products
class User:
def __init__(self, store: Store):
self.money = 0
self.store = store
self.belongs = []
def set_money(self, money):
self.money = money
def set_belongs(self, belongs):
self.belongs = belongs
def get_money(self):
return self.money
def get_belongs(self):
return self.belongs
def get_store(self):
return self.store
def see_product(self, product_id):
products = self.store.get_products()
return products[product_id]
def purchase_product(self, product_id):
product = self.see_product(product_id)
if self.money >= product["price"]:
self.store.products.pop(product_id)
self.money -= product["price"]
self.store.money += product["price"]
self.belongs.append(product)
return product
else:
raise Exception("잔돈이 부족합니다")
if __name__ == "__main__":
user_a = User(store=GrabStore())
user_b = User(store=FruitsStore())
문제 2. Store에 있는 상품과 돈을 마음대로 접근할 수 있다.
문제 1. 다른 Store가 온다면?
1) Store 추상화
2) User에 Store 의존성 주입
문제 2. Store에 있는 상품과 돈을 마음대로 접근할 수 있다.
1) Store의 책임을 정의하고 캡슐화
2) User의 결제 로직 수정
3) User 캡슐화
from abc import ABC, abstractmethod
class Store(ABC):
@abstractmethod
def __init__(self):
self.money = 0
self.name = ""
self.products = {}
@abstractmethod
def show_product(self, product_id):
pass
@abstractmethod
def give_product(self, product_id):
pass
@abstractmethod
def take_money(self, money):
pass
class GrabStore(Store):
def __init__(self, products):
self._money = 0
self.name = "그랩마켓"
self._products = products
def set_money(self, money):
self._money = money
def set_products(self, products):
self._products = products
def show_product(self, product_id):
return self._products[product_id]
def give_product(self, product_id):
self._products.pop(product_id)
def take_money(self, money):
self._money += money
class User:
def __init__(self, money, store: Store):
self.money = 0
self.store = store
self.belongs = []
def set_store(self, store):
self.store = store
def get_money(self):
return self.money
def get_belongs(self):
return self.belongs
def get_store(self):
return self.store
def see_product(self, product_id):
products = self.store.show_product(product_id=product_id)
return product
def purchase_product(self, product_id):
product = self.see_product(product_id)
if self.money >= product["price"]:
self.store.give_product(product_id)
self.money -= product["price"]
self.store.take_money(product["price"])
self.belongs.append(product)
return product
else:
raise Exception("잔돈이 부족합니다")
if __name__ == "__main__":
store = Grabstore(
products = {
1: {"name": "키보드", "price": 30000},
2: {"name": "모니터", "price": 50000}
}
)
user = User(money=100000, store=store)
user.purchase_product(product_id=1)
print(f"user가 구매한 상품: {user.get_belongs()}")
문제 3. 상품 판매 책임이 유저에 있다
문제 1. 다른 Store가 온다면?
1) Store 추상화
2) User에 Store 의존성 주입
문제 2. Store에 있는 상품과 돈을 마음대로 접근할 수 있다.
1) Store의 책임을 정의하고 캡슐화
2) User의 결제 로직 수정
3) User 캡슐화
문제 3. 상품 판매 책임이 User에 있다
1) Store에서 판매를 추상화하고, 구체 로직을 이동한다.
from abc import ABC, abstractmethod
class Store(ABC):
@abstractmethod
def __init__(self):
self.money = 0
self.name = ""
self.products = {}
@abstractmethod
def show_product(self, product_id):
pass
@abstractmethod
def sell_product(self, product_id, money):
pass
@abstractmethod
def take_money(self, money):
pass
class GrabStore(Store):
def __init__(self, products):
self._money = 0
self.name = "그랩마켓"
self._products = products
def set_money(self, money):
self._money = money
def set_products(self, products):
self._products = products
def show_product(self, product_id):
return self._products[product_id]
def sell_product(self, product_id, money):
product = self.show_product(product_id=product_id)
if not product:
raise Exception("상품이 존재하지 않음")
self._take_money(money=money)
try:
_product = self._take_out_product(product_id=product_id)
return _product
except Exception as e:
self._return_money(money)
raise e
def _take_out_product(self, product_id)
return self._products.pop(product_id)
def _take_money(self, money):
self._money += money
def _return_money(self, money):
self._money -= money
class User:
def __init__(self, money, store: Store):
self._money = money
self.store = store
self.belongs = []
def set_store(self, store):
self.store = store
def get_money(self):
return self._money
def get_belongs(self):
return self.belongs
def get_store(self):
return self.store
def see_product(self, product_id):
products = self.store.show_product(product_id=product_id)
return product
def purchase_product(self, product_id):
product = self.see_product(product_id)
price = product["price"]
if self._money >= price:
self._give_money(money=price)
try:
my_product = self.store.sell_product(product_id=product_id, money=price)
self._add_belong(my_product)
except Exception as e:
self._take_money(money=price)
print(f"구매 중 문제 발생 {str(e)}")
return product
else:
raise Exception("잔돈이 부족합니다")
def _give_money(self, money):
self._money -= money
def _take_money(self, money):
self._money += money
def _add_belong(self, money):
self.belongs.append(product)
if __name__ == "__main__":
store = Grabstore(
products = {
1: {"name": "키보드", "price": 30000},
2: {"name": "모니터", "price": 50000}
}
)
user = User(money=100000, store=store)
user.purchase_product(product_id=1)
print(f"user가 구매한 상품: {user.get_belongs()}")
문제 4. product가 책임을 가지자
문제 1. 다른 Store가 온다면?
1) Store 추상화
2) User에 Store 의존성 주입
문제 2. Store에 있는 상품과 돈을 마음대로 접근할 수 있다.
1) Store의 책임을 정의하고 캡슐화
2) User의 결제 로직 수정
3) User 캡슐화
문제 3. 상품 판매 책임이 User에 있다
1) Store에서 판매를 추상화하고, 구체 로직을 이동한다.
문제 4. product가 책임을 가지자, 리터럴을 없애자
1) 딕셔너리 타입을 클래스(데이터클래스: 필드데이터, 타입체킹 도움) 객체로 변환
2) 구체적 로직 새 메서드로 추출
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: int
class Store(ABC):
@abstractmethod
def __init__(self):
self._money = 0
self.name = ""
self._products = {}
@abstractmethod
def show_product(self, product_id):
pass
@abstractmethod
def sell_product(self, product_id, money):
pass
@abstractmethod
def take_money(self, money):
pass
class GrabStore(Store):
def __init__(self, products):
self._money = 0
self.name = "그랩마켓"
self._products = products
def set_money(self, money):
self._money = money
def set_products(self, products):
self._products = products
def show_product(self, product_id):
return self._products[product_id]
def sell_product(self, product_id, money):
product = self.show_product(product_id=product_id)
if not product:
raise Exception("상품이 존재하지 않음")
self._take_money(money=money)
try:
_product = self._take_out_product(product_id=product_id)
return _product
except Exception as e:
self._return_money(money)
raise e
def _take_out_product(self, product_id)
return self._products.pop(product_id)
def _take_money(self, money):
self._money += money
def _return_money(self, money):
self._money -= money
class User:
def __init__(self, money, store: Store):
self._money = money
self.store = store
self.belongs = []
def set_store(self, store):
self.store = store
def get_money(self):
return self._money
def get_belongs(self):
return self.belongs
def get_store(self):
return self.store
def see_product(self, product_id):
products = self.store.show_product(product_id=product_id)
return product
def purchase_product(self, product_id):
product = self.see_product(product_id)
price = product["price"]
if self._check_money_enough(price=price):
self._give_money(money=price)
try:
my_product = self.store.sell_product(product_id=product_id, money=price)
self._add_belong(my_product)
except Exception as e:
self._take_money(money=price)
print(f"구매 중 문제 발생 {str(e)}")
return product
else:
raise Exception("잔돈이 부족합니다")
def _check_money_enough(self, price):
return self._money >= price
def _give_money(self, money):
self._money -= money
def _take_money(self, money):
self._money += money
def _add_belong(self, money):
self.belongs.append(product)
if __name__ == "__main__":
store = Grabstore(
products = {
1: Product(name="키보드", price=30000),
2: Product(name="모니터", price=50000)
}
)
user = User(money=100000, store=store)
user.purchase_product(product_id=1)
print(f"user가 구매한 상품: {user.get_belongs()}")