• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • Python 設計模式——用模式改善軟件設計

    發表于:2007-07-04來源:作者:點擊數: 標簽:
    一、什么是設計模式 設計模式(design pattern)的提出,是 面向對象 程序設計演化過程中的一個重要里程碑。正如Gamma,Helm,Johnson和Vlissides在他們的經典著作《設計模式》一書中所說的:設計模式使得人們可以更加簡單和方便地去復用成功的軟件設計和體

      一、什么是設計模式
      設計模式(design pattern)的提出,是面向對象程序設計演化過程中的一個重要里程碑。正如Gamma,Helm,Johnson和Vlissides在他們的經典著作《設計模式》一書中所說的:設計模式使得人們可以更加簡單和方便地去復用成功的軟件設計和體系結構,從而能夠幫助設計者更快更好地完成系統設計。
      
      設計模式的概念最早起源于建筑設計大師Christopher Alexander關于城市規劃和建筑設計的著作《建筑的永恒方法》,盡管Alexander的著作是針對建筑領域的,但他的觀點實際上適用于所有的工程設計領域,其中就包括軟件設計領域。在《建筑的永恒方法》一書中,Alexander是這樣描述模式的:
      
      模式是一條由三部分組成的規則,它表示了一個特定環境、一個問題和一個解決方案之間的關系。每一個模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重復勞動。
      
      將設計模式引入軟件設計和開發過程的目的在于充分利用已有的軟件開發經驗,這是因為設計模式通常是對于某一類軟件設計問題的可重用的解決方案。優秀的軟件設計師都非常清楚,不是所有的問題都需要從頭開始解決,他們更愿意復用以前曾經使用過的解決方案,每當他們找到一個好的解決方案,他們會一遍又一遍地使用,這些經驗是他們成為專家的部分原因。設計模式的最終目標就是幫助人們利用熟練的軟件設計師的集體經驗,來設計出更加優秀的軟件。
      
      在軟件設計領域中,每一個設計模式都系統地命名、解釋和評價了面向對象系統中的一個重要的和可復用的設計。這樣,我們只要搞清楚這些設計模式,就可以完全或者說很大程度上吸收了那些蘊含在模式中的寶貴經驗,從而對軟件體系結構有了比較全面的了解。更加重要的是,這些模式都可以直接用來指導面向對象系統設計中至關重要的對象建模問題,實際工作中一旦遇到具有相同背景的場合,只需要簡單地套用這些模式就可以了,從而省去了很多摸索工作。
      
      二、經典的設計模式MVC
      在長期的軟件實踐過程中,人們逐漸總結出了一些實用的設計模式,并將它們應用于具體的軟件系統中,出色地解決了很多設計上的難題。源于Smalltalk,并在Java中得到廣泛應用的模型-視圖-控制器(Model-View-Controller,MVC)模式,是非常經典的一個設計模式,通過它你可以更好地理解"模式"這一概念。
      
      MVC模式通常用在開發人機交互軟件的時候,這類軟件的最大特點就是用戶界面容易改變,例如,當你要擴展一個應用程序的功能時,通常需要修改菜單來反映這種變化。如果用戶界面和核心功能緊緊交織在一起,要建立這樣一個靈活的系統通常是非常困難的,因為很容易產生錯誤。為了更好地開發這樣的軟件系統,系統設計師必須考慮下面兩個因素:
      
      用戶界面應該是易于改變的,甚至在運行期間也是有可能改變的;
      用戶界面的修改或移植不會影響軟件的核心功能代碼。
      為了解決這個問題,可以采用將模型(Model)、視圖(View)和控制器(Controller)相分離的思想。在這種設計模式中,模型用來封裝核心數據和功能,它獨立于特定的輸出表示和輸入行為,是執行某些任務的代碼,至于這些任務以什么形式顯示給用戶,并不是模型所關注的問題。模型只有純粹的功能性接口,也就是一系列的公開方法,這些方法有的是取值方法,讓系統其它部分可以得到模型的內部狀態,有的則是置值方法,允許系統的其它部分修改模型的內部狀態。
      
      視圖用來向用戶顯示信息,它獲得來自模型的數據,決定模型以什么樣的方式展示給用戶。同一個模型可以對應于多個視圖,這樣對于視圖而言,模型就是可重用的代碼。一般來說,模型內部必須保留所有對應視圖的相關信息,以便在模型的狀態發生改變時,可以通知所有的視圖進行更新。
      
      控制器是和視圖聯合使用的,它捕捉鼠標移動、鼠標點擊和鍵盤輸入等事件,將其轉化成服務請求,然后再傳給模型或者視圖。整個軟件的用戶是通過控制器來與系統交互的,他通過控制器來操縱模型,從而向模型傳遞數據,改變模型的狀態,并最后導致視圖的更新。
      
      MVC設計模式將模型、視圖與控制器三個相對獨立的部分分隔開來,這樣可以改變軟件的一個子系統而不至于對其它子系統產生重要影響。例如,在將一個非圖形化用戶界面軟件修改為圖形化用戶界面軟件時,不需要對模型進行修改,而添加一個對新的輸入設備的支持,則通常不會對視圖產生任何影響。
      
      應用了MVC設計模式的軟件系統,其基本的實現過程是:
      
      控制器創建模型;
      控制器創建一個或多個視圖,并將它們與模型相關聯;
      控制器負責改變模型的狀態;
      當模型的狀態發生改變時,模型會通知與之相關的視圖進行更新。
      如果用UML來表示MVC設計模式,則如圖1所示:
      

     


      三、Python與設計模式
      盡管設計模式的目標是努力做到與語言的無關性,但事實上許多模式在應用時還是需要依賴于具體實現語言的某些特性,尤其是該語言的對象模型。由于《設計模式》一書采用的是C++和Smalltalk來講述設計模式,因此訪問控制符和靜態成員方法(類方法)等都可以直接使用,可惜的是這些特性在Python中都無法用到,原因是Python采了與C++完全不同的對象模式。
      
      簡單說來,Python是一種優秀的面向對象腳本語言,它具有動態語義和快速的原型開發能力,也許在短短的幾分鐘內,你就可以開發出使用其它語言可能需要花費幾個小時的原型系統。Python豐富的工具集使得它位于傳統腳本語言(如Tcl、Perl和Scheme)和系統編程語言(如C、C++和Java)之間,既具備了腳本語言的簡單易用性,同時又能夠提供只有系統語言才可能擁有的某些高級特性。
      
      從面向對象角度來看,Python和Smalltalk一樣都采用了完全的面向對象設計思想,其對象模型能夠支持諸如運算符重載、多重繼承等高級概念。但Python在設計時似乎忽略了面向對象的一項基本原則,那就是數據隱藏。與C++和Java不同,Python沒有為類定義提供public、protected和private等關鍵字,這就意味著任何人都可以直接修改對象的屬性。Python之所以這么做,也許是為了保證語法上的簡潔性,就像Python的發明人Guido" van Rossum所認為的那樣:"豐富的語法帶來的負擔多于幫助"。但在某些設計模式中,向外界隱藏數據和方法都是非常必要的,為此我們不得不利用Python對象模型提供的某些高級特性,來實現某種程度上的隱藏性。
      
      在Python中應用設計模式的一個有利因素是它的動態類型綁定,也就是說一個對象很少只是一個類的實例,而是可以在運行時動態改變。在面向對象系統中,接口是一個基本的組成部分,對象只有通過它們的接口才能與外界進行交互。對象的接口與其功能是完全分離的,支持相同請求的不同對象針對同一請求所觸發的操作可能完全不同,這就是動態綁定的概念。動態綁定雖然看起來在一定程度上使得代碼不同那么容易理解和維護,但它的確可以使整個軟件系統的結構顯得更加清晰和合理。
      
      作為一門優秀的腳本語言,Python正在被越來越多的人所接受,使用Python開發的項目也越來越多,這也難怪會被大家推崇為"下一代編程語言"中的典型代表。隨著應用范圍的不斷擴展,如何在用Python開發軟件時充分利用已有的經驗和成果將成為人們關注的焦點,而設計模式作為軟件復用的一個重要方面,其價值自然是不言而喻??蓡栴}是目前所使用的設計模式大都是人們在用Smalltalk、C++和Java開發軟件時所總結出來的,因此或多或少地帶有這些語言的影子,而要想在Python中使用這些設計模式,必須根據Python的自身特點和實際需要,靈活地加以運用。
      
      四、Python對象模型
      對一門具體的編程語言來說,在應用設計模式時影響最大的莫過于它的對象模型了,這是因為大部分設計模式都源自于C++和Java這類面向對象編程語言。要想在Python中復用這些設計模式,首先需要對Python的對象模型有一個比較清晰的認識。
      
      4.1 類
      
      同其它面向對象編程語言一樣,Python中的類也是一種用戶自定義的數據類型,其基本的語法格式是:
      
          class (superclass, ...): # 定義類
             data = value # 共享的類變量
             def method(self, ...): # 類中的方法
              self.member = value # 實例的數據
          
      
      類定義從關鍵字class開始,并包含整個縮進代碼塊,類中定義的方法和屬性構成了類的名字空間(name space)。一個類通常會有多個方法,它們都以關鍵字def開頭,并且第一個參數通常都是self,Python中的變量self相當于C++中的關鍵字this,其作用是傳遞一個對象的引用。
      
      Python中的類屬性位于類的名字空間中,可以被所有的類實例所共享,這一點同C++和Java相同。訪問類屬性時不需要事先創建類的實例,直接使用類名就可以了。例如:
      
      >>> class Friend:
        default_age = 20
      
      >>> Friend.default_age
      20
      
      除了自定義的類屬性外,Python中的每個類其實都具有一些特殊的類屬性,它們都是由Python的對象模型所提供的。表1列出了這些類屬性:
      

     


      表1特殊的類屬性
      4.2" 實例
      
      定義類的目的是為了創建它的實例,從面向對象的角度看,類是對數據及其相關操作的封裝,而類實例則是對現實生活中某個實體的抽象。假設定義了如下一個類:
      
      
          class School:
             def __init__(self, name):
               self.name = name
               self.students = []
             def addStudent(self, student):
               self.students.append(student)
          
      
      要創建School類的一個實例,可以執行下面的語句:
      
      bit = School("Beijing Institute of Technology")
      
      在C++和Java中創建類實例時,與類具有相同名稱的構造函數被調用,而在Python中創建一個類的實例時,將調用名為__init__的特殊方法。Python中的類實例繼承了類的所有方法和屬性,并且有自己獨立的名字空間,使用下面的方法可以訪問類實例的方法和屬性:
      
      bit.addStudent("gary")
      bit.students
      
      Python中的對象屬性有一個非常有趣的地方,那就是使用它們之前不用像C++和Java那樣,必須先在類中進行聲明,因為這些都是可以動態創建的。作為一門動態類型語言,Python的這一特性的確非常靈活,但有時也難免產生問題。例如在許多針對接口的設計模式中,通常都需要知道對象所屬的類,以便能夠調用不同的實現方法,這些在C++和Java這些強類型語言的對象模型中不難實現,但對Python來講可就不那么簡單了,因為Python中的每個變量事實上都沒有固定的類型。
      
      為了解決這一問題,Python的__builtin__模塊提供了兩個非常實用的內建函數:isinstance()和issubclass()。其中函數isinstance()用于測試一個對象是否是某個類的實例,如果是的話則返回1,否則返回0。其基本的語法格式是:
      
      isinstance (instance_object, class_object)
      
      例如:
      
      
      >>> class Test:
        pass
      
      >>> inst = Test()
      >>> isinstance(inst, Test)
      1
      
      而函數issubclass()則用于測試一個類是否是另一個類的子類,如果是的話則返回1,否則返回0。其基本的語法格式是:
      
      issubclass(classobj1, classobj2)
      
      例如:
      
      
      >>> class TestA:
       pass
      
      >>> class TestB(TestA):
       pass
      
      >>> issubclass(TestA, TestB)
      0
      >>> issubclass(TestB, TestA)
      1
      
      和類一樣,Python中的每個類實例也具有一些特殊的屬性,它們都是由Python的對象模型所提供的。表2列出了這些屬性:
      


      表2" 特殊的實例屬性
      4.3繼承
      
      在面向對象的程序設計中,繼承(Inheritance)允許子類從父類那里獲得屬性和方法,同時子類可以添加或者重載其父類中的任何方法。在Python中定義繼承類的語法格式是:
      
      class (superclass, superclass, ...)
        suit
      
      例如,對于下面這個類:
      
      
          class Employee:
             def __init__(self, name, salary = 0):
               self.name = name
               self.salary = salary
             def raisesalary(self, percent):
               self.salary = self.salary * (1 + percent)
             def work(self):
               print self.name, "writes computer code"
          
      可以為其定義如下的子類:
      
      
          class Designer(Employee):
             def __init__(self, name):
               Employee.__init__(self, name, 5000)
             def work(self):
               print self.name, "writes design document"
          
      在C++和Java的對象模型中,子類的構造函數會自動調用父類的構造函數,但在Python中卻不是這樣,你必須在子類中顯示調用父類的構造函數,這就是為什么在Designer. __init__方法中必須調用Employee.__init__方法的原因。
      
      人們對多重繼承的看法一直褒貶不一,C++對象模型允許多重繼承,而Java對象模型則是通過接口(Interface)來間接實現多重繼承的。在對多重繼承的處理上,Python采用了和C++類似的方法,即允許多重繼承,例如:
      
      
        class A:
         pass
        class B(A):
         pass
        class C:
         pass
        class D(B, C):
         pass
        
      
      4.4 多態
      
      嚴格說來,像C++和Java這些強類型語言對象模型中的多態概念并不適用于Python,因為Python沒有提供類型聲明機制。但由于Python本身是一種動態類型語言,允許將任意值賦給任何一個變量,如果我們對多態的概念稍加擴充,將其理解為具有能同時處理多種數據類型的函數或方法,那么Python對象模型實際上也支持經過弱化后的多態。
      
      Python直到代碼運行之時才去決定一個變量所屬的類型,這一特性稱為運行時綁定(runtime binding)。Python解析器內部雖然也對變量進行類型分配,但卻十分模糊,并且只有在真正使用它們時才隱式地分配類型。例如,如果程序調用abs(num),則除數字之外的任何類型對變量num都沒有意義,此時變量num事實上就進行了非正式的類型分配。
      
      能夠處理不同抽象層次的對象,是面向對象編程最重要的特性之一,也是Python的一個非常重要的組成部分。下面的例子示范了如何讓Python中的一個函數能夠同時處理多種類型的數據,在C++的對象模型中,這種多態被稱為方法重載。
      
            class Polymorph:
               def deal_int(self, arg):
                 print '%d is an integer' % arg
               def deal_str(self, arg):
                 print '%s is a string' % arg
               def deal(self, arg):
                 if type(arg) == type(1):
                  self.deal_int(arg)
                 elif type(arg) == type(' '):
                  self.deal_str(arg)
                 else:
                  print '%s is not an integer or a strin

    [1] [2] 下一頁

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>