如果在IT行業的時間夠長的話,可能還記得大約10幾年前,設計模式風靡一時的時候,有過一段反 "if" 的運動。 所謂的反"if"運動,其實是誇大了"if"語句帶來的問題,比如當時提出的問題有: 代碼不好維護,特別是if或者else中的代碼比較多的時候 if和 else if分支太多的時候,代碼難以閱 ...
如果在IT行業的時間夠長的話,可能還記得大約10幾年前,設計模式風靡一時的時候,有過一段反 "if"
的運動。
所謂的反"if"
運動,其實是誇大了"if"
語句帶來的問題,比如當時提出的問題有:
- 代碼不好維護,特別是
if
或者else
中的代碼比較多的時候 if
和else if
分支太多的時候,代碼難以閱讀和修改- 閱讀含有
if
的代碼時,必須在自己的頭腦中模擬執行,會消耗你的精神能量 - ... ... 等等
這些問題確實存在,但是因為這些就徹底禁止if
的話,就過於極端,因噎廢食了。
代碼中分支和迴圈是不可避免的,完全禁止if
之後,在某些時候會產生了更加複雜和令人髮指的代碼,
所以,最後這個反"if"
的運動也不了了之,慢慢消亡了。
不過,為了反"if"
而產生的一些替代方案,我挑了三個還值得一看的方案,供大家參考參考。
其它還有很多方案都不太靠譜,就不一一贅述了。
1. 拆分成多個方法
這種重構"if"
的方法是將每個分支單獨封裝成一個獨立的方法。
比如:
def select_model(is_regression=True):
if is_regression:
print("選擇【回歸】模型")
else:
print("選擇【分類】模型")
# 測試代碼
select_model(True)
select_model(False)
# 運行結果
選擇【回歸】模型
選擇【分類】模型
示例中,方法select_model
通過is_regression
參數來決定調用哪種模型。
重構之後:
def select_regression():
print("選擇【回歸】模型")
def select_classifier():
print("選擇【分類】模型")
# 測試代碼
select_regression()
select_classifier()
# 運行結果
選擇【回歸】模型
選擇【分類】模型
將原方法拆分為兩個新方法,"if"
就消失了。
2. 改成多態
如果一個函數中分支比較多,比如:
def cry(animal):
if animal == "dog":
print("{} :汪汪~".format(animal))
elif animal == "cat":
print("{} :喵喵~".format(animal))
elif animal == "sheep":
print("{} :咩咩~".format(animal))
elif animal == "cow":
print("{} :哞哞~".format(animal))
else:
print("無法識別動物:{}".format(animal))
# 測試代碼
cry("dog")
cry("cat")
cry("sheep")
cry("cow")
# 運行結果
dog :汪汪~
cat :喵喵~
sheep :咩咩~
cow :哞哞~
cry
函數根據不同的參數來判斷輸出內容,
如果分支多了,並且每個分支中的代碼也比較多的時候,會比較難於維護。
對於上面的"if"
分支較多的情況,可以用多態的方式來改造。
也就是,封裝一個抽象類,其中包含抽象方法cry
,然後不同的動物繼承抽象類實現自己的cry
方法。
from abc import ABCMeta, abstractclassmethod
class Animal(metaclass=ABCMeta):
def __init__(self, name) -> None:
self.name = name
@abstractclassmethod
def cry(self):
pass
class Dog(Animal):
def __init__(self) -> None:
super().__init__("dog")
def cry(self):
print("{} :汪汪~".format(self.name))
class Cat(Animal):
def __init__(self) -> None:
super().__init__("cat")
def cry(self):
print("{} :喵喵~".format(self.name))
class Sheep(Animal):
def __init__(self) -> None:
super().__init__("sheep")
def cry(self):
print("{} :咩咩~".format(self.name))
class Cow(Animal):
def __init__(self) -> None:
super().__init__("cow")
def cry(self):
print("{} :哞哞~".format(self.name))
# 測試代碼
animal = Dog()
animal.cry()
animal = Cat()
animal.cry()
animal = Sheep()
animal.cry()
animal = Cow()
animal.cry()
# 運行結果
dog :汪汪~
cat :喵喵~
sheep :咩咩~
cow :哞哞~
3. 將條件判斷內聯
對於比較複雜的條件判斷,可以用內聯的方式的來改善。
比如,下麵構造一個略微複雜的判斷:
def complex_judge(foo, bar, baz):
if foo:
if bar:
return True
if baz:
return True
else:
return False
# 測試代碼
print(complex_judge(True, True, False))
print(complex_judge(True, False, False))
print(complex_judge(False, True, True))
# 運行結果
True
False
True
這樣寫不僅閱讀比較困難,增加或修改判斷條件時也很麻煩。
用內聯的方式(也就是用 and
和 or
)修改後,簡潔很多。
def complex_judge(foo, bar, baz):
return foo and bar or baz
# 測試代碼
print(complex_judge(True, True, False))
print(complex_judge(True, False, False))
print(complex_judge(False, True, True))
# 運行結果
True
False
True
4. 總結
反"if"
運動早已結束,對"if"
徹底拋棄顯得很荒謬,但也不能對此全盤否定。"if"
語句會影響閱讀代碼時流暢的思路,對代碼中"if"
的使用保持慎重的態度還是很有必要的。