您好,登錄后才能下訂單哦!
這篇文章主要介紹Python編程應(yīng)用設(shè)計(jì)原則的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
單一職責(zé)原則(Single Responsibility Principle)這個(gè)原則的英文描述是這樣的:A class or module should have a single responsibility。如果我們把它翻譯成中文,那就是:一個(gè)類或者模塊只負(fù)責(zé)完成一個(gè)職責(zé)(或者功能)。
讓我們舉一個(gè)更簡單的例子,我們有一個(gè)數(shù)字 L = [n1, n2, …, nx] 的列表,我們計(jì)算一些數(shù)學(xué)函數(shù)。例如,計(jì)算最大值、平均值等。
一個(gè)不好的方法是讓一個(gè)函數(shù)來完成所有的工作:
import numpy as np def math_operations(list_): # Compute Average print(f"the mean is {np.mean(list_)}") # Compute Max print(f"the max is {np.max(list_)}") math_operations(list_ = [1,2,3,4,5]) # the mean is 3.0 # the max is 5
實(shí)際開發(fā)中,你可以認(rèn)為 math_operations 很龐大,揉雜了各種功能代碼。
為了使這個(gè)更符合單一職責(zé)原則,我們應(yīng)該做的第一件事是將函數(shù) math_operations 拆分為更細(xì)粒度的函數(shù),一個(gè)函數(shù)只干一件事:
def get_mean(list_): '''Compute Max''' print(f"the mean is {np.mean(list_)}") def get_max(list_): '''Compute Max''' print(f"the max is {np.max(list_)}") def main(list_): # Compute Average get_mean(list_) # Compute Max get_max(list_) main([1,2,3,4,5]) # the mean is 3.0 # the max is 5
這樣做的好處就是:
易讀易調(diào)試,更容易定位錯(cuò)誤。
可復(fù)用,代碼的任何部分都可以在代碼的其他部分中重用。
可測(cè)試,為代碼的每個(gè)功能創(chuàng)建測(cè)試更容易。
但是要增加新功能,比如計(jì)算中位數(shù),main 函數(shù)還是很難維護(hù),因此還需要第二個(gè)原則:OCP。
開閉原則(Open Closed Principle)就是對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉,這可以大大提升代碼的可維護(hù)性,也就是說要增加新功能時(shí)只需要添加新的代碼,不修改原有的代碼,這樣做即簡單,也不會(huì)影響之前的單元測(cè)試,不容易出錯(cuò),即使出錯(cuò)也只需要檢查新添加的代碼。
上述代碼,可以通過將我們編寫的所有函數(shù)變成一個(gè)類的子類來解決這個(gè)問題。代碼如下:
import numpy as np from abc import ABC, abstractmethod class Operations(ABC): '''Operations''' @abstractmethod def operation(): pass class Mean(Operations): '''Compute Max''' def operation(list_): print(f"The mean is {np.mean(list_)}") class Max(Operations): '''Compute Max''' def operation(list_): print(f"The max is {np.max(list_)}") class Main: '''Main''' def get_operations(list_): # __subclasses__ will found all classes inheriting from Operations for operation in Operations.__subclasses__(): operation.operation(list_) if __name__ == "__main__": Main.get_operations([1,2,3,4,5]) # The mean is 3.0 # The max is 5
如果現(xiàn)在我們想添加一個(gè)新的操作,例如:median,我們只需要添加一個(gè)繼承自 Operations 類的 Median 類。新形成的子類將立即被 __subclasses__()
接收,無需對(duì)代碼的任何其他部分進(jìn)行修改。
里式替換原則的英文是 Liskov Substitution Principle,縮寫為 LSP。這個(gè)原則最早是在 1986 年由 Barbara Liskov 提出,他是這么描述這條原則的:
If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。
也就是說 子類對(duì)象能夠替換程序中父類對(duì)象出現(xiàn)的任何地方,并且保證原來程序的邏輯行為不變及正確性不被破壞。
實(shí)際上,里式替換原則還有另外一個(gè)更加能落地、更有指導(dǎo)意義的描述,那就是按照協(xié)議來設(shè)計(jì),子類在設(shè)計(jì)的時(shí)候,要遵守父類的行為約定(或者叫協(xié)議)。父類定義了函數(shù)的行為約定,那子類可以改變函數(shù)的內(nèi)部實(shí)現(xiàn)邏輯,但不能改變函數(shù)原有的行為約定。這里的行為約定包括:函數(shù)聲明要實(shí)現(xiàn)的功能;對(duì)輸入、輸出、異常的約定;甚至包括注釋中所羅列的任何特殊說明。
接口隔離原則的英文翻譯是 Interface Segregation Principle,縮寫為 ISP。Robert Martin 在 SOLID 原則中是這樣定義它的:Clients should not be forced to depend upon interfaces that they do not use。
直譯成中文的話就是:客戶端不應(yīng)該被強(qiáng)迫依賴它不需要的接口。其中的 客戶端 ,可以理解為接口的調(diào)用者或者使用者。
舉個(gè)例子:
from abc import ABC, abstractmethod class Mammals(ABC): @abstractmethod def swim(self) -> bool: pass @abstractmethod def walk(self) -> bool: pass class Human(Mammals): def swim(self)-> bool: print("Humans can swim") return True def walk(self)-> bool: print("Humans can walk") return True class Whale(Mammals): def walk(self) -> bool: print("Whales can't walk") return False def swim(self): print("Whales can swim") return True human = Human() human.swim() human.walk() whale = Whale() whale.swim() whale.walk()
執(zhí)行結(jié)果:
Humans can swim
Humans can walk
Whales can swim
Whales can't walk
事實(shí)上,子類鯨魚不應(yīng)該依賴它不需要的接口 walk,針對(duì)這種情況,就需要對(duì)接口進(jìn)行拆分,代碼如下:
from abc import ABC, abstractmethod class Swimer(ABC): @abstractmethod def swim(self) -> bool: pass class Walker(ABC): @abstractmethod def walk(self) -> bool: pass class Human(Swimer,Walker): def swim(self)-> bool: print("Humans can swim") return True def walk(self)-> bool: print("Humans can walk") return True class Whale(Swimer): def swim(self): print("Whales can swim") return True human = Human() human.swim() human.walk() whale = Whale() whale.swim()
依賴反轉(zhuǎn)原則的英文翻譯是 Dependency Inversion Principle,縮寫為 DIP。英文描述:High-level modules shouldn't depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn't depend on details. Details depend on abstractions。
我們將它翻譯成中文,大概意思就是:高層模塊不要依賴低層模塊。高層模塊和低層模塊應(yīng)該通過抽象(abstractions)來互相依賴。除此之外,抽象不要依賴具體實(shí)現(xiàn)細(xì)節(jié),具體實(shí)現(xiàn)細(xì)節(jié)依賴抽象。
在調(diào)用鏈上,調(diào)用者屬于高層,被調(diào)用者屬于低層,我們寫的代碼都屬于低層,由框架來調(diào)用。在平時(shí)的業(yè)務(wù)代碼開發(fā)中,高層模塊依賴低層模塊是沒有任何問題的,但是在框架層面設(shè)計(jì)的時(shí)候,就要考慮通用性,高層應(yīng)該依賴抽象的接口,低層應(yīng)該實(shí)現(xiàn)對(duì)應(yīng)的接口。如下圖所示:
也就是說本來 ObjectA 依賴 ObjectB,但為了擴(kuò)展后面可能會(huì)有 ObjectC,ObjectD,經(jīng)常變化,因此為了頻繁改動(dòng),讓高層模塊依賴抽象的接口 interface,然后讓 ObjectB 也反過來依賴 interface,這就是依賴反轉(zhuǎn)原則。
舉個(gè)例子,wsgi 協(xié)議就是一種抽象接口,高層模塊有 uWSGI,gunicorn等,低層模塊有 Django,F(xiàn)lask 等,uWSGI,gunicorn 并不直接依賴 Django,F(xiàn)lask,而是通過 wsgi 協(xié)議進(jìn)行互相依賴。
依賴倒置原則概念是高層次模塊不依賴于低層次模塊。看似在要求高層次模塊,實(shí)際上是在規(guī)范低層次模塊的設(shè)計(jì)。低層次模塊提供的接口要足夠的抽象、通用,在設(shè)計(jì)時(shí)需要考慮高層次模塊的使用種類和場景。明明是高層次模塊要使用低層次模塊,對(duì)低層次模塊有依賴性。現(xiàn)在反而低層次模塊需要根據(jù)高層次模塊來設(shè)計(jì),出現(xiàn)了「倒置」的顯現(xiàn)。
這樣設(shè)計(jì)好處有兩點(diǎn):
低層次模塊更加通用,適用性更廣
高層次模塊沒有依賴低層次模塊的具體實(shí)現(xiàn),方便低層次模塊的替換
以上是“Python編程應(yīng)用設(shè)計(jì)原則的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。