通過工廠函數對 __init__() 加以利用
我們可以通過工廠函數來構建一副完整的撲克牌。這會比枚舉所有52張撲克牌要好得多,在Python中,我們有如下兩種常見的工廠方法:
定義一個函數,該函數會創建所需類的對象。 定義一個類,該類有創建對象的方法。這是一個完整的工廠設計模式,正如設計模式書所描述的那樣。在諸如Java這樣的語言中,工廠類層次結構是必須的,因為該語言不支持獨立的函數。 在Python中,類并不是必須的。只是當有相關的工廠非常復雜的時候才會顯現出優勢。Python的優勢就是當一個簡單的函數可以做的更好的時候我們決不強迫使用類層次結構。 雖然這是一本關于面向對象編程的書,但函數真是一個好東西。這在Python中是常見的也是最地道的。如果需要的話,我們總是可以將一個函數重寫為適當的可調用對象。我們可以將一個可調用對象重構到我們的工廠類層次結構中。我們將在第五章《使用可調用對象和上下文》中學習可調用對象。
一般,類定義的優點是通過繼承實現代碼重用。工廠類的函數就是包裝一些目標類層次結構和復雜對象的構造。如果我們有一個工廠類,當擴展目標類層次結構的時候,我們可以添加子類到工廠類中。這給我們提供了多態性工廠類;不同的工廠類定義具有相同的方法簽名,可以交替使用。
這類水平的多態性對于靜態編譯語言如Java或C++非常有用。編譯器可以解決類和方法生成代碼的細節。
如果選擇的工廠定義不能重用任何代碼,則在Python中類層次結構不會有任何幫助。我們可以簡單的使用具有相同簽名的函數。
以下是我們各種Card子類的工廠函數:
def card(rank, suit): if rank == 1: return AceCard('A', suit) elif 2 <= rank < 11: return NumberCard(str(rank), suit) elif 11 <= rank < 14: name = {11: 'J', 12: 'Q', 13: 'K' }[rank] return FaceCard(name, suit) else: raise Exception("Rank out of range")
這個函數通過數值類型的rank和suit對象構建Card類。我們現在可以非常簡單的構建牌了。我們已經封裝構造問題到一個單一的工廠函數中,允許應用程序在不知道精確的類層次結構和多態設計是如何工作的情況下進行構建。
下面是一個如何通過這個工廠函數構建一副牌的示例:
deck = [card(rank, suit) for rank in range(1,14) for suit in (Club, Diamond, Heart, Spade)]
它枚舉了所有的牌值和花色來創建完整的52張牌。
1. 錯誤的工廠設計和模糊的else子句
注意card()函數里面的if語句結構。我們沒有使用“包羅萬象”的else子句來做任何處理;我們只是拋出異常。使用“包羅萬象”的else子句會引出一個小小的辯論。
新聞熱點
疑難解答