Заметки Романа Теличкина

Вредный рефакторинг

Ноябрь 2019
В конце заметки "Рефакторинг от души" я зачем-то создал сложного и уродливого объектно-ориентированного монстра. Вот он: 
class GildedRose:
    @staticmethod
    def update_quality(items):
        for item in items:
            item.update_quality()

        return items


class Item:
    def __new__(cls, name, sell_in, quality):
        item_class = {
            "Aged Brie": SpecialItem,
            "Backstage passes to a TAFKAL80ETC concert": SpecialItem,
            "Sulfuras, Hand of Ragnaros": ImmutableItem,
        }.get(name, DefaultItem)

        return item_class(sell_in, quality)


class ImmutableItem:
    def __init__(self, sell_in, quality):
        self.sell_in = sell_in
        self.quality = quality

    def update_quality(self):
        pass


class DefaultItem(ImmutableItem):
    def update_quality(self):
        self.sell_in = self.sell_in - 1

        self.quality = cond(
            (self.sell_in >= 0, self.quality - 1),
            (self.sell_in < 0, self.quality - 2))

        self.quality = max(0, self.quality)


class SpecialItem(ImmutableItem):
    def update_quality(self):
        self.sell_in = self.sell_in - 1

        self.quality = cond(
            (self.sell_in < 0, 0),
            (self.sell_in < 6, self.quality + 3),
            (self.sell_in < 11, self.quality + 2),
            (self.sell_in >= 11, self.quality + 1))

        self.quality = min(50, self.quality)


def cond(*args):
    for is_true, returnable in args:
        if is_true:
            return returnable
Решить проблему — не цель этого кода. Настоящая цель — показать, что я умнее читателя и знаю больше ООП трюков. Для решения проблемы не нужны никакие классы с методом __new__, не нужно наследование, достаточно императивного кода с привычным ветвлением из if-ов:
class GildedRose:
    @staticmethod
    def update_quality(items):
        for item in items:
            if item.name == 'Sulfuras, Hand of Ragnaros':
                continue

            item.sell_in -= 1

            if item.name in ['Aged Brie', 'Backstage passes to a TAFKAL80ETC concert']:
                if item.sell_in <= 0:
                    item.quality = 0
                elif item.sell_in <= 5:
                    item.quality += 3
                elif item.sell_in <= 10:
                    item.quality += 2
                elif item.sell_in > 10:
                    item.quality += 1
            else:
                if item.sell_in >= 0:
                    item.quality -= 1
                elif item.sell_in < 0:
                    item.quality -= 2

            if item.quality < 0:
                item.quality = 0
            elif item.quality > 50:
                item.quality = 50


class Item:
    def __init__(self, name, sell_in, quality):
        self.name = name
        self.sell_in = sell_in
        self.quality = quality
Спустя пять лет самообучения программированию мой код стал превращаться в код пятилетней давности, который решает проблему самым банальным способом.
Открыть комментарии