最近在讀《深入淺出設計模式》這一本書,收穫頗多,打算寫一個系列的blog,並用python實現其中的每一個設計模式,以加深理解。
下面將要介紹的就是書中的第一個設計模式:策略模式
書中以類比鴨子應用問題作為執行個體,一款遊戲應用中要求有各種各樣的鴨子。
先用繼承來實現了這一個應用,其設計如下:
這個設計主要是以Duck類作為基類,後面所有的鴨子類均以此類派生而來,剛開始在應用還不是很複雜的時候,似乎還沒有什麼問題,但當派生出來的類(鴨子的類型)越來越多時,問題就出現了。並不是所有的鴨子都會飛的,比如像皮鴨子就不會飛。也不是所有的鴨子都會呱呱叫,也有鴨子吱吱叫。也許你會說,我可以在衍生類別中重寫基類的方法,從而達到應用的要求,實現不同的鴨子有不同的叫法,不同的飛行方式。但是有一個問題不能解決,重寫函數並不應該改變原有函數的行為,比如fly()這個函數,不能飛的鴨子就不應該有fly()這個函數存在。而如果我們只是重寫基類的fly()函數,看起來是不合適的。並且quack()函數用於發出“呱呱叫”,而基類中定義了quack()就意味著所有的鴨子中都有quck(),如果現在要求鴨子“吱吱叫”,怎麼辦呢。在基類中添加一個"吱吱叫“的函數。那這樣又會影響到其它的子類。
如此看來,派生並不解決問題最好的辦法,或者說不能只用派生來解問題。
分析一下,得到以下設計原則: 針對介面編程,而不是實現編程 分離應用中經常變化的部分
最終,我們分開了易於變化的部分,飛行行為和呱呱叫行為,設計出來的類圖如下:
我用python代碼實現如下:
''' The first Design Pattern: Strategy Pattern.KeyNote: Identify the aspects of your application that vary and separate them from what stays the same.'''class FlyBehavior: ''' Interface class: FlyBehavior ''' def fly(self): returnclass FlyWithWing(FlyBehavior): def fly(self): print 'I am flying with wings!'class FlyNoWay(FlyBehavior): def fly(self): print 'I cannot fly!'class QuackBehavior: ''' Interface Behavior: QuackBehavior ''' def quack(self): returnclass Quack(QuackBehavior): def quack(self): print 'Quack!'class Squeak(QuackBehavior): def quack(self): print 'Squeak'class MuteQuack(QuackBehavior): def quack(self): print 'MuteQuack'class Duck: '''Base class: Duck. All ducks are inherent from this class''' def __init__(self, flyParam, quackParam): self.flyBehavior = flyParam self.quackBehavior = quackParam def performFly(self): self.flyBehavior.fly() def performQuack(self): self.quackBehavior.quack() def swim(self): print 'All ducks can swim...' return def display(self): returnclass RedDuck(Duck): def __init__(self, flyParam=FlyWithWing(), quackParam=MuteQuack()): Duck.__init__(self, flyParam, quackParam) def display(self): print 'I am a red duck!' returnclass RubberDuck(Duck): def __init__(self, flyParam=FlyNoWay(), quackParam=Quack()): Duck.__init__(self, flyParam, quackParam) def display(self): print 'I am a rubber duck!'duck = RedDuck()duck.display()duck.performFly()duck.performQuack()duck.swim()duck = RubberDuck()duck.display()duck.performFly()duck.performQuack()duck.swim()