mirror of
https://github.com/emilybache/GildedRose-Refactoring-Kata.git
synced 2026-02-04 09:11:39 +00:00
291 lines
7.9 KiB
Python
Executable File
291 lines
7.9 KiB
Python
Executable File
"""Gilded Rose Refactoring Kata."""
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
AGED_BRIE: str = "Aged Brie"
|
|
BACKSTAGE_PASSES: str = "Backstage passes to a TAFKAL80ETC concert"
|
|
CONJURED: str = "Conjured"
|
|
MAX_QUALITY: int = 50
|
|
MIN_QUALITY: int = 0
|
|
SULFURAS: str = "Sulfuras, Hand of Ragnaros"
|
|
SULFURAS_QUALITY: int = 80
|
|
|
|
class ItemUpdateStrategy(ABC):
|
|
"""Abstract base class for item update strategies."""
|
|
|
|
@abstractmethod
|
|
def update_quality(self, item: Item) -> None:
|
|
"""Update the quality of the given item according to specific rules.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item whose quality is to be updated.
|
|
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def update_sell_in(self, item: Item) -> None:
|
|
"""Update the sell_in of the given item according to specific rules.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item whose sell_in is to be updated.
|
|
|
|
"""
|
|
pass
|
|
|
|
class NormalItemStrategy(ItemUpdateStrategy):
|
|
"""Strategy for normal items that degrade in quality over time."""
|
|
|
|
def update_quality(self, item: Item) -> None:
|
|
"""Decrease quality by 1 before sell date, by 2 after.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
degradation: int = 2 if item.sell_in <= 0 else 1
|
|
item.quality = max(MIN_QUALITY, item.quality - degradation)
|
|
|
|
def update_sell_in(self, item: Item) -> None:
|
|
"""Decrease sell_in by 1 each day.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
item.sell_in -= 1
|
|
|
|
|
|
class AgedBrieStrategy(ItemUpdateStrategy):
|
|
"""Strategy for Aged Brie that increases in quality over time."""
|
|
|
|
def update_quality(self, item: Item) -> None:
|
|
"""Increase quality by 1 before sell date, by 2 after.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
increase: int = 2 if item.sell_in <= 0 else 1
|
|
item.quality = min(MAX_QUALITY, item.quality + increase)
|
|
|
|
def update_sell_in(self, item: Item) -> None:
|
|
"""Decrease sell_in by 1 each day.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
item.sell_in -= 1
|
|
|
|
|
|
class SulfurasStrategy(ItemUpdateStrategy):
|
|
"""Strategy for Sulfuras, a legendary item that never changes."""
|
|
|
|
def update_quality(self, item: Item) -> None:
|
|
"""Sulfuras quality never changes.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update (no actual change occurs).
|
|
|
|
"""
|
|
pass
|
|
|
|
def update_sell_in(self, item: Item) -> None:
|
|
"""Sulfuras never needs to be sold.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update (no actual change occurs).
|
|
|
|
"""
|
|
pass
|
|
|
|
|
|
class BackstagePassStrategy(ItemUpdateStrategy):
|
|
"""Strategy for Backstage passes with tiered quality appreciation."""
|
|
|
|
def update_quality(self, item: Item) -> None:
|
|
"""Update quality based on days until concert.
|
|
|
|
Quality increases by:
|
|
- 1 when more than 10 days remain
|
|
- 2 when 6-10 days remain
|
|
- 3 when 1-5 days remain
|
|
- drops to 0 after concert (sell_in < 0)
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
if item.sell_in <= 0:
|
|
item.quality = 0
|
|
elif item.sell_in <= 5:
|
|
item.quality = min(MAX_QUALITY, item.quality + 3)
|
|
elif item.sell_in <= 10:
|
|
item.quality = min(MAX_QUALITY, item.quality + 2)
|
|
else:
|
|
item.quality = min(MAX_QUALITY, item.quality + 1)
|
|
|
|
def update_sell_in(self, item: Item) -> None:
|
|
"""Decrease sell_in by 1 each day.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
item.sell_in -= 1
|
|
|
|
|
|
class ConjuredItemStrategy(ItemUpdateStrategy):
|
|
"""Strategy for Conjured items that degrade twice as fast as normal items."""
|
|
|
|
def update_quality(self, item: Item) -> None:
|
|
"""Decrease quality by 2 before sell date, by 4 after.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
degradation = 4 if item.sell_in < 0 else 2
|
|
item.quality = max(MIN_QUALITY, item.quality - degradation)
|
|
|
|
def update_sell_in(self, item: Item) -> None:
|
|
"""Decrease sell_in by 1 each day.
|
|
|
|
Parameters
|
|
----------
|
|
item : Item
|
|
The item to update.
|
|
|
|
"""
|
|
item.sell_in -= 1
|
|
|
|
class ItemStrategyFactory:
|
|
"""Factory for creating appropriate item update strategies.
|
|
|
|
Maps item names to their corresponding update strategies.
|
|
Centralizes the logic for determining which strategy to use.
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
"""Initialize the factory with strategy instances."""
|
|
self._normal = NormalItemStrategy()
|
|
self._aged_brie = AgedBrieStrategy()
|
|
self._sulfuras = SulfurasStrategy()
|
|
self._backstage = BackstagePassStrategy()
|
|
self._conjured = ConjuredItemStrategy()
|
|
|
|
def get_strategy(self, item_name: str) -> ItemUpdateStrategy:
|
|
"""Return the appropriate strategy for the given item name.
|
|
|
|
Parameters
|
|
----------
|
|
item_name : str
|
|
The name of the item.
|
|
|
|
Returns
|
|
-------
|
|
ItemUpdateStrategy
|
|
The strategy instance for updating this item type.
|
|
|
|
"""
|
|
if item_name == SULFURAS:
|
|
return self._sulfuras
|
|
elif item_name == AGED_BRIE:
|
|
return self._aged_brie
|
|
elif item_name == BACKSTAGE_PASSES:
|
|
return self._backstage
|
|
elif item_name.startswith(CONJURED):
|
|
return self._conjured
|
|
else:
|
|
return self._normal
|
|
|
|
class GildedRose:
|
|
"""Manages inventory quality updates for the Gilded Rose inn.
|
|
|
|
Updates item quality and sell_in values acording to specific business rules:
|
|
- Normal items degrade in quality over time
|
|
- "Aged Brie" increases in quality as it ages
|
|
- "Sulfuras" is a legendary item that never changes
|
|
- "Backstage passes" increase in quality as concert approaches, drop to 0 after
|
|
- Quality is never negative and never exceeds 50 (except Sulfuras at 80)
|
|
|
|
Goblin will throw a tantrum if the Item class is modified.
|
|
"""
|
|
|
|
def __init__(self, items: list[Item]) -> None:
|
|
"""Initialize the GildedRose with a list of items.
|
|
|
|
Parameters
|
|
----------
|
|
items : list[Item]
|
|
The list of items in the inventory.
|
|
|
|
"""
|
|
self.items = items
|
|
self._strategy_factory = ItemStrategyFactory()
|
|
|
|
def update_quality(self) -> None:
|
|
"""Update quality and sell_in for all items according to the business rules."""
|
|
for item in self.items:
|
|
strategy = self._strategy_factory.get_strategy(item.name)
|
|
strategy.update_quality(item)
|
|
strategy.update_sell_in(item)
|
|
|
|
class Item:
|
|
"""Represents an item in the Gilded Rose inventory.
|
|
|
|
This class must not be modidied cuz Goblin said so.
|
|
"""
|
|
|
|
def __init__(self, name: str, sell_in: int, quality: int) -> None:
|
|
"""Initialize an item in the Gilded Rose inventory.
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
The item's name, which determines its update behavior.
|
|
sell_in : int
|
|
Number of days remaining to sell the item.
|
|
quality : int
|
|
Current quality value (0-50 for normal items, 80 for Sulfuras).
|
|
|
|
"""
|
|
self.name = name
|
|
self.sell_in = sell_in
|
|
self.quality = quality
|
|
|
|
def __repr__(self) -> str:
|
|
"""Return a string representation of the item.
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
A string describing the item with its name, sell_in, and quality.
|
|
|
|
"""
|
|
return f"{self.name}, {self.sell_in}, {self.quality}"
|