自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

寫好 Python 代碼的幾條重要技巧

開發(fā) 后端
程序設(shè)計的好與壞,早在我們青蔥歲月時就接觸過了,只是那是并不知道這竟如此重要。能夠立即改善程序設(shè)計、寫出“好”代碼的知識有以下幾點。來看一下吧。

 程序設(shè)計的好與壞,早在我們青蔥歲月時就接觸過了,只是那是并不知道這竟如此重要。能夠立即改善程序設(shè)計、寫出“好”代碼的知識有以下幾點:

•  面向?qū)ο笪鍌€基本原則;

•  常見的三種架構(gòu);

•  繪圖;

•  起一個好名字;•優(yōu)化嵌套的 if else 代碼;

當(dāng)然,其他技術(shù)知識的豐富程度也決定了程序設(shè)計的好壞。例如通過引入消息隊列解決雙端性能差異問題、通過增加緩存層提高查詢效率等。下面我們一起來看看,上面列出的知識點包含哪些內(nèi)容,這些內(nèi)容對代碼和程序設(shè)計的改善有何幫助。

面向?qū)ο笪鍌€基本原則

本書作者是 2010 級學(xué)生,面向?qū)ο笫亲髡咔嗍[時期發(fā)展火熱的編程范式。它的五個基本原則是:

•  單一職責(zé)原則;

•  開放封閉原則;

•  依賴倒置原則;

•  接口隔離原則;

•  合成復(fù)用原則;

下面我們將通過對比和場景假設(shè)的方式了解五個基本原則對代碼質(zhì)量的影響。

立竿見影的單一職責(zé)原則

沒錯,立竿見影、效果卓越。對于我們這些自學(xué)編程無師自通的人來說,能把功能實現(xiàn)就可以了,根本沒有時間考慮代碼優(yōu)化和維護成本問題。時光流逝,竟在接觸編程很長一段時間后才發(fā)現(xiàn)它竟如此重要。

俗話說只要代碼寫的夠爛,提升就足夠明顯。以一個從文件內(nèi)容中匹配關(guān)鍵數(shù)據(jù)并根據(jù)匹配結(jié)果發(fā)出網(wǎng)絡(luò)請求的案例,看看大部分程序員的寫法: 

  1. import re  
  2. import requests  
  3. FILE = "./information.fet"  
  4. def extract(file): 
  5.      fil = open(file, "r")  
  6.     content = fil.read()  
  7.     fil.close()  
  8.     find_object = re.search(r"url=\d+", content)  
  9.     find = find_object.group(1)  
  10.     text = requests.get(find)  
  11.     return text  
  12. if __name__ == "__main__":  
  13.     text = extract(FILE)  
  14.     print(text) 

需求已經(jīng)實現(xiàn),這點毋庸置疑,但是問題來了:

•  如果讀取文件的時候發(fā)生異常了怎么辦?

•  如果數(shù)據(jù)源發(fā)生變化該如何處理?

•  如果網(wǎng)絡(luò)請求返回的數(shù)據(jù)不符合最終要求怎么辦?

如果你心里的第一個反應(yīng)是改代碼,那你就要注意了。完成一件事中間的某個環(huán)節(jié)發(fā)生變化,改代碼是在所難免的,但是如果按照上面這種寫法,不僅代碼越改越亂,連邏輯也會越來越亂。單一職責(zé)原則表達(dá)的是讓一個函數(shù)盡量只做一件事,不要將多件事混雜在一個函數(shù)中。

上面的代碼如果重新設(shè)計,我認(rèn)為至少應(yīng)該是這樣的: 

  1. def get_source():  
  2.     """獲取數(shù)據(jù)源"""  
  3.     return  
  4. def extract_(val):  
  5.     """匹配關(guān)鍵數(shù)據(jù)"""  
  6.     return  
  7. def fetch(val):  
  8.     """發(fā)出網(wǎng)絡(luò)請求"""  
  9.     return  
  10. def trim(val):  
  11.     """修剪數(shù)據(jù)"""  
  12.     return   
  13. def extract(file):  
  14.     """提取目標(biāo)數(shù)據(jù)"""  
  15.     source = get_source()  
  16.     content = extract_(source)  
  17.     text = trim(fetch(content))  
  18.     return text  
  19. if __name__ == "__main__":  
  20.     text = extract(FILE)  
  21.     print(text) 

把原來放在一個函數(shù)中實現(xiàn)的多個步驟拆分成為多個更小的函數(shù),每個函數(shù)只做一件事。當(dāng)數(shù)據(jù)源發(fā)生變化時,只需要改動 get_source 相關(guān)的代碼即可;如果網(wǎng)絡(luò)請求返回的數(shù)據(jù)不符合最終要求,我們可以在 trim 函數(shù)中對它進行修剪。這樣一來,代碼應(yīng)對變化的能力提高了許多,整個流程也變得更清晰易懂。改動前后的變化如下圖所示:

單一職責(zé)原則的核心是解耦和增強內(nèi)聚力,如果一個函數(shù)承擔(dān)的職責(zé)過多,等于把這些職責(zé)耦合在一起,這種耦合會導(dǎo)致脆弱的設(shè)計。當(dāng)發(fā)生變化時,原本的設(shè)計會遭受到意想不到的破壞。單一職責(zé)原則實際上是把一件事拆分成多個步驟,代碼修改造成的影響范圍很小。

讓代碼穩(wěn)定性飛升的開放封閉原則和依賴倒置原則

開放封閉原則中的開放指的是對擴展開放,封閉指的是對修改封閉。需求總是變化的,業(yè)務(wù)方這個月讓你把數(shù)據(jù)存儲到 MySQL 數(shù)據(jù)庫中,下個月就有可能讓你導(dǎo)出到 Excel 表格里,這時候你就得改代碼了。這個場景和上面的單一職責(zé)原則很相似,同樣面臨代碼改動,單一職責(zé)原則示例主要表達(dá)的是通過解耦降低改動的影響,這里主要表達(dá)的是通過對擴展開放、對修改封閉提高程序應(yīng)對變化的能力和提高程序穩(wěn)定性。

穩(wěn)定這個詞如何理解呢?

較少的改動或者不改動即視為穩(wěn)定,穩(wěn)定意味著調(diào)用這個對象的其它代碼拿到的結(jié)果是可以確定的,整體是穩(wěn)定的。

按照一般程序員的寫法,數(shù)據(jù)存儲的代碼大概是這樣的: 

  1. class MySQLSave:  
  2.     def __init__(self):  
  3.         pass  
  4.     def insert(self):  
  5.         pass  
  6.     def update(self):  
  7.         pass  
  8. class Business:  
  9.     def __init__(self):  
  10.         pass   
  11.     def save(self):  
  12.         saver = MySQLSave()  
  13.         saver.insert() 

功能是能夠?qū)崿F(xiàn)的,這點毋庸置疑。來看看它如何應(yīng)對變化,如果要更換存儲,那么就意味著需要改代碼。按照上面的代碼示例,有兩個選擇:

•  重新寫一個存儲到 ExcelSave 的類;

•  對 MySQLSave 類進行改動;

上面的兩種選擇,無論怎么選都會改動 2 個類。因為不僅存儲的類需要改動,調(diào)用處的代碼也需要更改。這樣一來,它們整體都是不穩(wěn)定的。如果換一種實現(xiàn)方式,根據(jù)依賴倒置的設(shè)計指導(dǎo)可以輕松應(yīng)對這個問題。邊看代碼邊理解: 

  1. import abc  
  2. class Save(metaclass=abc.ABCMeta):  
  3.     @abc.abstractmethod  
  4.     def insert(self):  
  5.         pass  
  6.     @abc.abstractmethod  
  7.     def update(self):  
  8.         pass  
  9. class MySQLSave(Save):  
  10.     def __init__(self):  
  11.         self.classify = "mysql"  
  12.         pass  
  13.     def insert(self):  
  14.         pass  
  15.     def update(self):  
  16.         pass  
  17. class Excel(Save):  
  18.     def __init__(self):  
  19.         self.classify = "excel"  
  20.     def insert(self):  
  21.         pass  
  22.     def update(self):  
  23.         pass  
  24. class Business:  
  25.     def __init__(self, saver):  
  26.         self.saver = saver  
  27.     def insert(self):  
  28.         self.saver.insert()  
  29.     def update(self):  
  30.         self.saver.update()  
  31. if __name__ == "__main__":  
  32.     mysql_saver = MySQLSave()  
  33.     excel_saver = Excel()  
  34.     business = Business(mysql_saver) 

這里通過內(nèi)置的 abc 實現(xiàn)了一個抽象基類,這個基類的目的是強制子類實現(xiàn)要求的方法,以達(dá)到子類功能統(tǒng)一。子類功能統(tǒng)一后,無論調(diào)用它的哪個子類,都是穩(wěn)定的,不會出現(xiàn)調(diào)用方還需要修改方法名或者修改傳入?yún)?shù)的情況。

依賴倒置中的倒置,指的是依賴關(guān)系的倒置。之前的代碼是調(diào)用方 Business 依賴對象 MySQLSave,一旦對象 MySQLSave 需要被替換, Business 就需要改動。依賴倒置中的依賴指的是對象的依賴關(guān)系,之前依賴的是實體,如果改為后面這種依賴抽象的方式,情況就會扭轉(zhuǎn)過來:

實體 Business 依賴抽象有一個好處:抽象穩(wěn)定。相對于多變的實體來說,抽象更穩(wěn)定。代碼改動前后的依賴關(guān)系發(fā)生了重大變化,之前調(diào)用方 Business 直接依賴于實體 MySQLSave,通過依賴倒置改造后 Busines 和 ExcelSave、 MySQLSave 全都依賴抽象。

這樣做的好處是如果需要更換存儲,只需要創(chuàng)建一個新的存儲實體,然后調(diào)用 Business 時傳遞進去即可,這樣可以不用改動 Business 的代碼,符合面向修改封閉、面向擴展開放的開放封閉原則;

依賴倒置的具體實現(xiàn)方式使用了一種叫做依賴注入的手段,實際上單純使用依賴注入、不使用依賴倒置也可以滿足開閉原則要求,感興趣的讀者不妨試一試。

挑肥揀瘦的接口隔離原則

接口隔離原則中的接口指的是 Interface,而不是 Web 應(yīng)用里面的 Restful 接口,但是在實際應(yīng)用中可以將其抽象理解為相同的對象。接口隔離原則在設(shè)計層面看,跟單一職責(zé)原則的目的是一致的。接口隔離原則的指導(dǎo)思想是:

•  調(diào)用方不應(yīng)該依賴它不需要的接口;

•  依賴關(guān)系應(yīng)當(dāng)建立在最小接口上;

這實際上是告訴我們要給接口減肥,過多功能的接口可以選用拆分的方式優(yōu)化。舉個例子,現(xiàn)在為圖書館設(shè)計一個圖書的抽象類: 

  1. import abc  
  2. class Book(metaclass=abc.ABCMeta):  
  3.     @abc.abstractmethod  
  4.     def buy(self):  
  5.         pass  
  6.     @abc.abstractmethod  
  7.     def borrow(self):  
  8.         pass  
  9.     @abc.abstractmethod  
  10.     def shelf_off(self):  
  11.         pass  
  12.     @abc.abstractmethod  
  13.     def shelf_on(self):  
  14.         pass 

圖可以被購買、可以被借閱、可以下架、可以上架,這看起來并沒有什么問題。但這樣一來這個抽象只能提供給管理人員使用,用戶操作時需要再設(shè)定一個新的抽象類,因為你不可能讓用戶可以操縱圖書上下架。接口隔離原則推薦的做法是把圖書的上下架和圖書購買、借閱分成 2 個抽象類,管理端的圖書類繼承 2 個抽象類,用戶端的圖書類繼承 1 個抽象類。這么看起來是有點繞,不要慌,我們看圖理解:

這樣是不是一下就看懂了。這個指導(dǎo)思想很重要,不僅能夠指導(dǎo)我們設(shè)計抽象接口,也能夠指導(dǎo)我們設(shè)計 Restful 接口,還能夠幫助我們發(fā)現(xiàn)現(xiàn)有接口存在的問題,從而設(shè)計出更合理的程序。

輕裝上陣的合成復(fù)用原則

合成復(fù)用原則的指導(dǎo)思想是:盡量使用對象組合,而不是繼承來達(dá)到復(fù)用的目的。合成復(fù)用的作用是降低對象之間的依賴,因為繼承是強依賴關(guān)系,無論子類使用到父類的哪幾個屬性,子類都需要完全擁有父類。合成采用另一種方式實現(xiàn)對象之間的關(guān)聯(lián),降低依賴關(guān)系。

為什么推薦優(yōu)先使用合成復(fù)用,而后考慮繼承呢?

因為繼承的強依賴關(guān)系,一旦被依賴的對象(父類)發(fā)生改變,那么依賴者(子類)也需要改變,合成復(fù)用則可以避免這樣的情況出現(xiàn)。要注意的是,推薦優(yōu)先使用復(fù)用,但并不是拒絕使用繼承,該用的地方還得用。我們以一段代碼為例,說明合成復(fù)用和繼承的差異: 

  1. import abc  
  2. class Car:  
  3.     def move(self):  
  4.         pass  
  5.     def engine(self):  
  6.         pass  
  7. class KateCar(Car):  
  8.     def move(self):  
  9.         pass  
  10.     def engine(self):  
  11.         pass  
  12. class FluentCar(Car): 
  13.     def move(self):  
  14.         pass  
  15.     def engine(self):  
  16.         pass 

這里的 Car 作為父類,擁有 move 和 engine 2 個重要屬性,這時候如果需要給汽車涂裝顏色,那么就要新增一個 color 屬性,3 個類都要增加。如果使用合成復(fù)用的方式,可以這么寫: 

  1. class Color:  
  2.     pass  
  3. class KateCar:  
  4.     color = Color()  
  5.     def move(self):  
  6.         pass  
  7.     def engine(self):  
  8.         pass  
  9. class FluentCar:  
  10.     color = Color()  
  11.     def move(self):  
  12.         pass  
  13.     def engine(self):  
  14.         pass 

類對象合成復(fù)用的具體操作是在類中實例化一個類對象,然后在需要的時候調(diào)用它。代碼可能沒有那么直觀,我們看圖:

這個例子主要用于說明繼承和合成復(fù)用的具體實現(xiàn)方式和前后變化,對于 Car 的繼承無需深究,因為如果你執(zhí)著地討論為什么右圖中的 2 個 Car 不用繼承,就會陷入牛角尖。

這里的合成復(fù)用選用的實現(xiàn)方式是在 2 個 Car 里面實例化另一個類 Color,其實也可以用依賴注入的手段在外部實例化 Color,然后把實例對象傳遞給 2 個 Car。

常見的三種架構(gòu)

了解多種不同的架構(gòu)可以使我們的知識面更寬廣,面對一類問題的時候可以提出其它解決辦法。同時,了解多種架構(gòu)可以讓我們在設(shè)計階段做好規(guī)劃,避免后續(xù)頻繁的重構(gòu)。常見的三種架構(gòu)分別是:

•  單體架構(gòu);

•  分布式架構(gòu);

•  微服務(wù)架構(gòu);

單體架構(gòu)

單體架構(gòu)是我們平時接觸較多的架構(gòu),也是相對容易理解的架構(gòu)。單體架構(gòu)把所有功能都聚合在一個應(yīng)用里,我們可以簡單地將這種架構(gòu)視作:

這種架構(gòu)簡單、容易部署和測試,大部分應(yīng)用的初期都采用單體架構(gòu)。單體架構(gòu)也有幾個明顯缺點:

•  復(fù)雜性高,所有功能糅合在一個應(yīng)用里,模塊多、容易出現(xiàn)邊界模糊,而且隨著時間的推移和業(yè)務(wù)的發(fā)展,項目越來越大、代碼越來越多,整體服務(wù)效率逐漸下降;

•  發(fā)布/部署頻率低,牽一發(fā)而動全身,新功能或問題修復(fù)的發(fā)布上線需要多方協(xié)調(diào),發(fā)布時間一拖再拖。項目大則構(gòu)建時間長、構(gòu)建失敗的幾率也會有所增加;

•  性能瓶頸明顯,一頭牛再厲害也抵不過多頭牛合力的效果,隨著數(shù)據(jù)量、請求并發(fā)的增加,讀性能的不足最先暴露出來,接著你就會發(fā)現(xiàn)其它方面也跟不上了;

•  影響技術(shù)創(chuàng)新:單體架構(gòu)通常選用一類語言或一類框架統(tǒng)一開發(fā),想要引入新技術(shù)或者接入現(xiàn)代化的服務(wù)是很困難的;

•  可靠性低,一旦服務(wù)出現(xiàn)問題,影響是巨大的。

分布式架構(gòu)

分布式架構(gòu)相對于單體架構(gòu)而言,通過拆分解決了單體架構(gòu)面臨的大部分問題,例如性能瓶頸。假如單體架構(gòu)是一頭牛,那么分布式架構(gòu)就是多頭牛:

當(dāng)單體架構(gòu)出現(xiàn)性能瓶頸時,團隊可以考慮將單體架構(gòu)轉(zhuǎn)換為分布式架構(gòu),以增強服務(wù)能力。當(dāng)然,分布式并不是萬能的,它解決了單體架構(gòu)性能瓶頸、可靠性低的問題,但復(fù)雜性問題、技術(shù)創(chuàng)新問題和發(fā)布頻率低依然存在,這時候可以考慮微服務(wù)。

微服務(wù)架構(gòu)

微服務(wù)架構(gòu)的關(guān)鍵字是拆,將原本糅合在一個應(yīng)用中的多個功能拆成多個小應(yīng)用,這些小應(yīng)用串聯(lián)起來組成一個與之前單體架構(gòu)功能相同的完整應(yīng)用。具體示意如下:

 

每個微服務(wù)可以獨立運行,它們之間通過網(wǎng)絡(luò)協(xié)議進行交互。每個微服務(wù)可以部署多個實例,這樣一來就具備了跟分布式架構(gòu)相同的性能。單個服務(wù)的發(fā)布/部署對其它服務(wù)的影響較小,在代碼上沒有關(guān)聯(lián),因此可以頻繁的發(fā)布新版本。復(fù)雜性的問題迎刃而解,拆分之后架構(gòu)邏輯清晰、功能模塊職責(zé)單一,功能的增加和代碼的增加也不會影響到整體效率。服務(wù)獨立之后,項目就變得語言無關(guān),評價服務(wù)可以用 Java 語言來實現(xiàn)也可以用 Golang 語言實現(xiàn),不再受到語言或者框架的制約,技術(shù)創(chuàng)新問題得以緩解。

這是不是很像單一職責(zé)原則和接口隔離原則?

分布式和微服務(wù)并不是銀彈

從上面的對比來看,似乎分布式架構(gòu)比單體架構(gòu)好,微服務(wù)架構(gòu)比分布式架構(gòu)好,這么說來微服務(wù)架構(gòu)>分布式架構(gòu)>單體架構(gòu)?

這么理解是不對的,架構(gòu)需要根據(jù)場景和需求選擇,微服務(wù)架構(gòu)和分布式架構(gòu)看上去很美,但也衍生出了許多新問題。以微服務(wù)架構(gòu)為例:

•  運維成本高,在單體架構(gòu)時,運維只需要保證 1 個應(yīng)用正常運行即可,關(guān)注的可能只是硬件資源消耗問題。但如果換成微服務(wù)架構(gòu),應(yīng)用的數(shù)量成百上千,當(dāng)應(yīng)用出現(xiàn)問題或者多應(yīng)用之間協(xié)調(diào)異常時,運維人員的頭就會變大;

•  分布式系統(tǒng)固有的復(fù)雜性,網(wǎng)絡(luò)分區(qū)、分布式事務(wù)、流量均衡對開發(fā)者和運維進行了敲打;

•  接口調(diào)整成本高,一個接口的調(diào)用方可能有很多個,如果設(shè)計時沒有遵循開放封閉原則和接口隔離原則,那么調(diào)整的工作量會是非常大的;

•  接口性能受限,原本通過函數(shù)調(diào)用的方式交互,在內(nèi)存中很快就完成了,換成接口后通過網(wǎng)絡(luò)進行交互,性能明顯下降;

•  重復(fù)勞動,雖然有公共模塊,但如果語言無關(guān)且又要考慮性能(不用接口交互)就需要自己實現(xiàn)一份相同功能的代碼;

到底用哪種架構(gòu),需要根據(jù)具體的場景來選擇。如果你的系統(tǒng)復(fù)雜度并沒有那么高、性能追求也沒有那么高,例如一個日數(shù)據(jù)量只有幾萬的爬蟲應(yīng)用,單體架構(gòu)就足以解決問題,不需要強行做成分布式或者微服務(wù),因為這樣只會增加自己的工作量。

畫好圖

在需要表達(dá)關(guān)系和邏輯梳理的場景里,圖永遠(yuǎn)比代碼好。業(yè)內(nèi)流行這么一句話“程序開發(fā),設(shè)計先行”,說的是在開發(fā)前,需要對程序進行構(gòu)思和設(shè)計。試想,如果連對象關(guān)系和邏輯都說不清楚,寫出的代碼會是好代碼嗎?

在構(gòu)思項目時可以使用用例圖挖掘需求和功能模塊;在架構(gòu)設(shè)計時可以使用協(xié)作圖梳理模塊關(guān)系;在設(shè)計接口或者類對象時可以使用類圖做好交互計劃;在功能設(shè)計時可以使用狀態(tài)圖幫助我們挖掘功能屬性……

了解繪圖的重要性之后,具體的繪圖方法和技巧可翻閱本書(《Python 編程參考》)的工程師繪圖指南章節(jié)展開學(xué)習(xí)。

起一個好名字

你還記得自己曾經(jīng)起過的那些名字嗎:

•  reversalList

•  get_translation

•  get_data

•  do_trim

•  CarAbstract

起一個好的、合適的名字能夠讓代碼風(fēng)格更統(tǒng)一,看上去清晰了然。起一個好名字不單單是單詞語法的問題,還會涉及風(fēng)格選擇和用途。具體的命名方法和技巧可翻閱本書(《Python 編程參考》)的命名選擇與風(fēng)格指南章節(jié)展開學(xué)習(xí)。

優(yōu)化嵌套的 if else 代碼

寫代碼的時候用一些控制語句是很正常的事,但是如果 if else 嵌套太多,也是非常頭疼的,代碼看上去就像下面這樣。

這種結(jié)構(gòu)的產(chǎn)生是因為使用了 if 語句來進行先決條件的檢查,如果負(fù)責(zé)條件則進入下一行代碼,如果不符合則停止。既然這樣,那我們在先決條件的檢查上進行取反即可,代碼改動過后看起來像這樣: 

  1. if "http" not in url:  
  2.         return  
  3. if "www" not in url:  
  4.         return 

這是我平時常用的優(yōu)化辦法,后來在張曄老師的付費專欄中看到這種手段的名稱——衛(wèi)語句。

當(dāng)然,這種簡單的邏輯處理和 if else 控制流用衛(wèi)語句進行處理是很有效的,但如果邏輯再復(fù)雜一些,用衛(wèi)語句的效果就不見的那么好了。假設(shè)汽車 4S 店有折扣權(quán)限限制,普通銷售有權(quán)對 30 萬以內(nèi)金額的汽車授予一定折扣,超過 30 萬但在 80 萬以內(nèi)需要精英銷售進行授權(quán),更高價格的車折扣需要店長授權(quán)。這個功能可以歸納為根據(jù)金額的大小來確定授權(quán)者,對應(yīng)代碼如下: 

  1. def buying_car(price):  
  2.     if price < 300000:  
  3.         print("普通銷售")  
  4.     elif price < 800000:  
  5.         print("精英銷售")  
  6.     elif price < 1500000:  
  7.         print("店長") 

代碼思路清晰,但存在的問題也明顯。如果以后擴展價格和定級,會增加更多的 if else 語句,代碼將變得臃腫??刂普Z句的順序是固定在代碼中的,如果想要調(diào)整順序,只能修改控制語句。

那么問題來了,有比 if else 更合適的辦法嗎?

這時候可以考慮一種叫做責(zé)任鏈的設(shè)計模式,責(zé)任鏈設(shè)計模式的定義為:為了避免請求發(fā)送者與多個請求處理者耦合在一起,于是將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當(dāng)有請求發(fā)生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。

看起來有點繞,我們通過代碼圖加深理解:

處理類執(zhí)行前根據(jù)先決條件判斷自身的 handler 是否能夠處理,如果不能則交給 next_handler,也就是責(zé)任鏈的下一個節(jié)點。上面的用責(zé)任鏈實現(xiàn)為: 

  1. class Manager:  
  2.     def __init__(self,):  
  3.         self.obj = None  
  4.     def next_handler(self, obj):  
  5.         self.obj = obj  
  6.     def handler(self, price):  
  7.         pass  
  8. class General(Manager):  
  9.     def handler(self, price):  
  10.         if price < 300000:  
  11.             print("{} 普通銷售".format(price))  
  12.         else:  
  13.             self.obj.handler(price)  
  14. class Elite(Manager):  
  15.     def handler(self, price):  
  16.         if 300000 <= price < 800000:  
  17.             print("{} 精英銷售".format(price))  
  18.         else:  
  19.             self.obj.handler(price)  
  20. class BOSS(Manager):  
  21.     def handler(self, price):  
  22.         if price >= 800000:  
  23.             print("{} 店長".format(price)) 

創(chuàng)建好抽象類和具體的處理類之后,它們還沒有關(guān)聯(lián)關(guān)系。我們需要將它們掛載到一起,成為一個鏈條: 

  1. general = General()  
  2. elite = Elite()  
  3. boss = BOSS()  
  4. general.next_handler(elite)  
  5. elite.next_handler(boss) 

這里建立的責(zé)任鏈順序為 General -> Elite -> BOSS,調(diào)用方只需要傳遞價格給 General,如果它沒有折扣的授予權(quán)它會交給 Elite 處理,如果 Elite 沒有折扣授予權(quán)則會交給 BOSS 處理。對應(yīng)代碼如下: 

  1. prices = [550000, 220000, 1500000, 200000, 330000]  
  2. for price in prices:  
  3.     general.handler(price)   

這跟我們?nèi)?4S 店購車是一樣的,作為客戶,我們確定好要買的車即可,至于 4S 店如何申請折扣,誰來授權(quán)與我無關(guān),我能拿到相應(yīng)的折扣即可。

至此,if else 優(yōu)化知識學(xué)習(xí)完畢。 

 

責(zé)任編輯:龐桂玉 來源: 馬哥Linux運維
相關(guān)推薦

2009-08-12 14:01:17

C# Excel編程技

2020-07-31 08:12:49

代碼機器設(shè)備

2022-02-09 18:15:10

語言宏定義軟件

2011-11-25 10:35:20

Java

2020-07-03 14:50:23

Python代碼編程語言

2020-09-06 08:19:11

Python編程語言開發(fā)

2021-07-19 15:12:21

Python編程語言

2021-10-13 08:16:14

SQL 代碼系統(tǒng)

2022-04-08 09:35:36

JavaScript代碼

2015-10-26 09:57:10

程序員既要代碼好文檔

2011-04-01 11:31:05

VB

2021-04-08 09:42:17

程序員技能開發(fā)者

2015-10-28 15:04:06

程序員好代碼好文檔

2012-07-23 10:22:15

Python性能優(yōu)化優(yōu)化技巧

2024-11-25 16:08:57

Python代碼代碼調(diào)試

2014-12-15 14:39:00

Java

2023-03-27 15:05:10

Python技巧

2020-08-14 09:59:31

Python開發(fā)工具

2020-05-06 09:53:56

敏捷開發(fā)IT主管CIO

2020-05-06 11:10:28

Python代碼開發(fā)
點贊
收藏

51CTO技術(shù)棧公眾號