為什麼用多態性替換條件有用? (Why is replacing conditionals with polymorphism useful?)


問題描述

為什麼用多態性替換條件有用? (Why is replacing conditionals with polymorphism useful?)

關於“用多態性替換條件”這件事一直困擾著我。如 refactoring.guru 我想澄清一下。我在下面的 python 中重新創建了示例:

IF 語句代碼

def get_speed(bird):
    base_speed = 10

    if bird == "AfricanBird":
        return base_speed * 2 ‑ 10
    elif bird=="EuropeanBird":
        return base_speed * 1.85 ‑ 12
    elif bird=="NorwegianBlue":
        return base_speed * 2.5 ‑ 11
    else:
        raise ValueError("Bird type invalid")

if __name__=="__main__":
    b = "EuropeanBird"
    speed = get_speed(b)
    print(speed)

用多態替換 IF 語句

from abc import abstractmethod, ABC

class Bird(ABC):
    def get_base_speed(self):
        return 10

    @abstractmethod
    def get_speed(self):
        pass

class AfricanBird(Bird):
    def get_speed(self):
        return self.get_base_speed()*2‑10

class EuropeanBird(Bird):
    def get_speed(self):
        return self.get_base_speed()*1.85‑12

class NorwegianBlue(Bird):
    def get_speed(self):
        return self.get_base_speed()*2.5‑11

if __name__=="__main__":
    # This *still* has to be specified by the user somewhere.
    # For example in a GUI or input text file.
    b = "EuropeanBird"

    # Here is the if statement again!!
    if b == "AfricanBird":
        b = AfricanBird()
    elif b=="EuropeanBird":
        b = EuropeanBird()
    elif b=="NorwegianBlue":
        b = NorwegianBlue()
    else:
        raise ValueError("Bird type invalid")

    print(b.get_speed())

我得到了多態性增加通用性的部分,它允許您從基類繼承並重新定義行為,而不是在 if 語句中添加新分支。然而,歸根結底,您仍然需要在主代碼中的某處決定要使用基類的 which 實現(我的第二個示例中的第 26 行),這會強制 if 語句重新出現。

我錯過了重點嗎?有什麼辦法可以徹底消除客戶端代碼中的條件語句?


參考解法

方法 1:

In the IF STATEMENT variant, the cases must be handled alongside the computation. In the POLYMORPHISM variant, the cases can be handled as early as receiving the input, but could also be pushed arbitrarily further along. Using Polymorphism, the case decision and result are decoupled; one could even re‑use the same decision to derive multiple results.

In short, both require to make the decision somewhere but Polymorphism allows choosing this somewhere.


While logically, something has to conditionally switch between the cases, this can be done without explicitly enumerating if branches.

The simplest means is to have a table from identifier to type. The base class can encapsulate this:

class Bird(ABC):
    _birdies = {}
    _base_speed = 10

    @classmethod
    def breed(cls, kind: str):
        """Create a new bird of a given kind"""
        return cls._birdies[kind]()

    # register subclasses for lookup on definition
    def __init_subclass__(cls):
        Bird._birdies[cls.__name__] = cls

    @property
    @abstractmethod
    def speed(self):
        raise NotImplementedError

class AfricanBird(Bird):
    @property
    def speed(self):
        return self._base_speed * 2 ‑ 10

class EuropeanBird(Bird):
    @property
    def speed(self):
        return self._base_speed * 1.85 ‑ 12

Bird.breed("AfricanBird")  # <__main__.AfricanBird at 0x1106d1fa0>

Note that the class is only used as a frontend to hide the table. There is no polymorphism used here other than assuming that all subclasses can be interchangeably constructed without arguments.

方法 2:

In your example, you are converting a mere string to a full hierarchy of classes. As all what if required is handling a string, and as the input is that string, the polymorphism adds nothing except learning.

Things are different when various objects are created internally, and when those objects have some common behaviour with specificities. In fact the choice should arise at conception time, before writing any code line. You analyse what objects are to be processed, and what behaviour they will have to implement. At that point, the possible hierarchies of classes should arise.

In fact, replacing a bunch of conditional with polymorphism should only occur if you have skipped the modeling phase in development, and find yourself consistently repeating the same conditional throughout your code. I have been using Python, Java and C++ for decades, and have never replaced conditionals with polymorphism: either the model exhibits a hierarchy at conception time, and it has to be implemented first, or there are no underlying objects and polymorphism will only add an useless complexity.

TL/DR: if you find yourself replacing conditionals with polymorphism, it just mean that you have written code without first thinking about what you wanted to develop and how you should to it.

(by user32882MisterMiyagiSerge Ballesta)

參考文件

  1. Why is replacing conditionals with polymorphism useful? (CC BY‑SA 2.5/3.0/4.0)

#conditional-statements #polymorphism #Python #OOP #design-patterns






相關問題

在 SSRS 中使用條件來提高可見性 (using conditionals in SSRS for visibility)

Smarty - {IF} {/IF} 內的條件太多 (Smarty - Too many conditions inside {IF} {/IF})

awk 如果有多個條件拋出錯誤 (awk if with multiple condition throws error)

正則表達式錯誤,嵌套標籤 (Regex error, nested tags)

警告:分配條件 (Warning: Assignment in condition)

JavaScript 中的條件語句 (Conditional Statement in JavaScript)

與 linus 條件 '-z' '-n' 混淆 (Confuse with the linus conditions '-z' '-n')

如果條件為真,則將表達式添加到循環中 (if condition is true, add an expression to a loop)

為什麼用多態性替換條件有用? (Why is replacing conditionals with polymorphism useful?)

如何使用條件將一個數據框列的值與另一個數據框列的值匹配? (How do you match the value of one dataframe's column with another dataframe's column using conditionals?)

使用另一個數據框的條件創建一個新列 (Create a new column with a condition of another dataframe)

排除具有空值的 Python 列表 (Excluding Python Lists With Empty Values)







留言討論