为什么用多态替换条件很有用?
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())
我得到了多态性增加通用性的部分,它允许您从基础 class 继承并重新定义行为,而不是在 if
语句中添加新分支。然而,在一天结束时,您仍然需要在主代码的某个地方做出决定,以便使用 哪个 实现您的基础 class (我的第二个示例中的第 26 行),这会强制 if
语句重新出现。
我是不是漏掉了重点?有什么办法可以完全去掉客户端代码中的条件语句吗?
在您的示例中,您只是将字符串转换为 类 的完整层次结构。由于所有需要的都是处理字符串,并且输入是该字符串,因此多态性除了学习之外什么也没增加。
当在内部创建各种对象时,以及当这些对象具有一些具有特殊性的共同行为时,情况就不同了。事实上,选择应该在构思时出现,在编写任何代码行之前。您分析要处理哪些 个对象 ,以及它们必须实现的行为。到那时,应该会出现 类 的可能层次结构。
事实上,只有当您跳过了开发中的建模阶段并发现自己在整个代码中始终重复相同的条件时,才应该用多态替换一堆条件。几十年来,我一直在使用 Python、Java 和 C++,并且从未用多态性替换条件:要么模型在构思时 表现出层次结构,并且它必须首先实现,否则没有底层对象,多态只会增加无用的复杂性。
TL/DR:如果您发现自己用多态替换了条件语句,那只是意味着您在编写代码时没有首先考虑要开发什么以及应该如何开发。
在 IF STATEMENT 变体中,案例 必须 与计算一起处理。在 POLYMORPHISM 变体中,案例 可以 在接收到输入时尽早处理,但也可以任意进一步推进。使用多态性,案例决策和结果解耦;甚至可以重复使用相同的决定来得出多个结果。
简而言之,两者都需要在某处做出决定,但多态性允许在某处选择。
虽然从逻辑上讲,something 必须有条件地在 case 之间切换,但无需显式枚举 if
分支即可完成。
最简单的方法是从标识符到类型有一个table。基础class可以封装这个:
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>
请注意 class 仅用作隐藏 table 的前端。除了假设所有子 class 都可以在没有参数的情况下互换构造之外,这里没有使用多态性。
关于“用多态替换条件”,有一件事一直困扰着我,如 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())
我得到了多态性增加通用性的部分,它允许您从基础 class 继承并重新定义行为,而不是在 if
语句中添加新分支。然而,在一天结束时,您仍然需要在主代码的某个地方做出决定,以便使用 哪个 实现您的基础 class (我的第二个示例中的第 26 行),这会强制 if
语句重新出现。
我是不是漏掉了重点?有什么办法可以完全去掉客户端代码中的条件语句吗?
在您的示例中,您只是将字符串转换为 类 的完整层次结构。由于所有需要的都是处理字符串,并且输入是该字符串,因此多态性除了学习之外什么也没增加。
当在内部创建各种对象时,以及当这些对象具有一些具有特殊性的共同行为时,情况就不同了。事实上,选择应该在构思时出现,在编写任何代码行之前。您分析要处理哪些 个对象 ,以及它们必须实现的行为。到那时,应该会出现 类 的可能层次结构。
事实上,只有当您跳过了开发中的建模阶段并发现自己在整个代码中始终重复相同的条件时,才应该用多态替换一堆条件。几十年来,我一直在使用 Python、Java 和 C++,并且从未用多态性替换条件:要么模型在构思时 表现出层次结构,并且它必须首先实现,否则没有底层对象,多态只会增加无用的复杂性。
TL/DR:如果您发现自己用多态替换了条件语句,那只是意味着您在编写代码时没有首先考虑要开发什么以及应该如何开发。
在 IF STATEMENT 变体中,案例 必须 与计算一起处理。在 POLYMORPHISM 变体中,案例 可以 在接收到输入时尽早处理,但也可以任意进一步推进。使用多态性,案例决策和结果解耦;甚至可以重复使用相同的决定来得出多个结果。
简而言之,两者都需要在某处做出决定,但多态性允许在某处选择。
虽然从逻辑上讲,something 必须有条件地在 case 之间切换,但无需显式枚举 if
分支即可完成。
最简单的方法是从标识符到类型有一个table。基础class可以封装这个:
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>
请注意 class 仅用作隐藏 table 的前端。除了假设所有子 class 都可以在没有参数的情况下互换构造之外,这里没有使用多态性。