成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何在 Python 中應用設計原則

開發 后端
什么是好用的代碼呢?其實就是代碼質量比較高,如何評價代碼質量的高低呢?最常用的、最重要的評價標準,就是代碼的可維護性、可讀性、可擴展性、靈活性、簡潔性、可復用性、可測試性。

[[408977]]

寫出能用的代碼很簡單,寫出好用的代碼很難。

什么是好用的代碼呢?其實就是代碼質量比較高,如何評價代碼質量的高低呢?最常用的、最重要的評價標準,就是代碼的可維護性、可讀性、可擴展性、靈活性、簡潔性、可復用性、可測試性。

好用的代碼,也都會遵循一此原則,這就是設計原則,它們分別是:

  • 單一職責原則 (SRP)
  • 開閉原則 (OCP)
  • 里氏替換原則 (LSP)
  • 接口隔離原則 (ISP)
  • 依賴倒置原則 (DIP)

提取這五種原則的首字母縮寫詞,就是 SOLID 原則。下面分別進行介紹,并展示如何在 Python 中應用。

1、單一職責原則 SRP

單一職責原則(Single Responsibility Principle)這個原則的英文描述是這樣的:A class or module should have a single responsibility。如果我們把它翻譯成中文,那就是:一個類或者模塊只負責完成一個職責(或者功能)。

讓我們舉一個更簡單的例子,我們有一個數字 L = [n1, n2, …, nx] 的列表,我們計算一些數學函數。例如,計算最大值、平均值等。

一個不好的方法是讓一個函數來完成所有的工作:

  1. import numpy as np 
  2.  
  3. def math_operations(list_): 
  4.     # Compute Average 
  5.     print(f"the mean is {np.mean(list_)}"
  6.     # Compute Max 
  7.     print(f"the max is {np.max(list_)}")  
  8.  
  9. math_operations(list_ = [1,2,3,4,5]) 
  10. # the mean is 3.0 
  11. # the max is 5 

實際開發中,你可以認為 math_operations 很龐大,揉雜了各種功能代碼。

為了使這個更符合單一職責原則,我們應該做的第一件事是將函數 math_operations 拆分為更細粒度的函數,一個函數只干一件事:

  1. def get_mean(list_): 
  2.     '''Compute Max''' 
  3.     print(f"the mean is {np.mean(list_)}")  
  4.  
  5. def get_max(list_): 
  6.     '''Compute Max''' 
  7.     print(f"the max is {np.max(list_)}")  
  8.  
  9. def main(list_):  
  10.     # Compute Average 
  11.     get_mean(list_) 
  12.     # Compute Max 
  13.     get_max(list_) 
  14.  
  15. main([1,2,3,4,5]) 
  16. # the mean is 3.0 
  17. # the max is 5 

這樣做的好處就是:

  • 易讀易調試,更容易定位錯誤。
  • 可復用,代碼的任何部分都可以在代碼的其他部分中重用。
  • 可測試,為代碼的每個功能創建測試更容易。

但是要增加新功能,比如計算中位數,main 函數還是很難維護,因此還需要第二個原則:OCP。

2、開閉原則 OCP

開閉原則(Open Closed Principle)就是對擴展開放,對修改關閉,這可以大大提升代碼的可維護性,也就是說要增加新功能時只需要添加新的代碼,不修改原有的代碼,這樣做即簡單,也不會影響之前的單元測試,不容易出錯,即使出錯也只需要檢查新添加的代碼。

上述代碼,可以通過將我們編寫的所有函數變成一個類的子類來解決這個問題。代碼如下:

  1. import numpy as np 
  2. from abc import ABC, abstractmethod 
  3.  
  4. class Operations(ABC): 
  5.     '''Operations''' 
  6.     @abstractmethod 
  7.     def operation(): 
  8.         pass 
  9.  
  10. class Mean(Operations): 
  11.     '''Compute Max''' 
  12.     def operation(list_): 
  13.         print(f"The mean is {np.mean(list_)}")  
  14.  
  15. class Max(Operations): 
  16.     '''Compute Max''' 
  17.     def operation(list_): 
  18.         print(f"The max is {np.max(list_)}")  
  19.  
  20. class Main: 
  21.     '''Main''' 
  22.     def get_operations(list_): 
  23.         # __subclasses__ will found all classes inheriting from Operations 
  24.         for operation in Operations.__subclasses__(): 
  25.             operation.operation(list_) 
  26.  
  27.  
  28. if __name__ == "__main__"
  29.     Main.get_operations([1,2,3,4,5]) 
  30. # The mean is 3.0 
  31. # The max is 5 

如果現在我們想添加一個新的操作,例如:median,我們只需要添加一個繼承自 Operations 類的 Median 類。新形成的子類將立即被 __subclasses__()接收,無需對代碼的任何其他部分進行修改。

3、里氏替換原則 (LSP)

里式替換原則的英文是 Liskov Substitution Principle,縮寫為 LSP。這個原則最早是在 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。

也就是說 子類對象能夠替換程序中父類對象出現的任何地方,并且保證原來程序的邏輯行為不變及正確性不被破壞。

實際上,里式替換原則還有另外一個更加能落地、更有指導意義的描述,那就是按照協議來設計,子類在設計的時候,要遵守父類的行為約定(或者叫協議)。父類定義了函數的行為約定,那子類可以改變函數的內部實現邏輯,但不能改變函數原有的行為約定。這里的行為約定包括:函數聲明要實現的功能;對輸入、輸出、異常的約定;甚至包括注釋中所羅列的任何特殊說明。

4、接口隔離原則 (ISP)

接口隔離原則的英文翻譯是 Interface Segregation Principle,縮寫為 ISP。Robert Martin 在 SOLID 原則中是這樣定義它的:Clients should not be forced to depend upon interfaces that they do not use。

直譯成中文的話就是:客戶端不應該被強迫依賴它不需要的接口。其中的 客戶端 ,可以理解為接口的調用者或者使用者。

舉個例子:

  1. from abc import ABC, abstractmethod 
  2. class Mammals(ABC): 
  3.  
  4.     @abstractmethod 
  5.     def swim(self) -> bool: 
  6.         pass 
  7.  
  8.     @abstractmethod 
  9.     def walk(self) -> bool: 
  10.         pass 
  11.  
  12.  
  13. class Human(Mammals): 
  14.     def swim(self)-> bool: 
  15.         print("Humans can swim"
  16.         return True 
  17.  
  18.     def walk(self)-> bool: 
  19.         print("Humans can walk"
  20.         return True 
  21.  
  22.  
  23. class Whale(Mammals): 
  24.  
  25.     def walk(self) -> bool: 
  26.         print("Whales can't walk"
  27.         return False 
  28.  
  29.     def swim(self): 
  30.         print("Whales can swim"
  31.         return True 
  32.  
  33.  
  34. human = Human() 
  35. human.swim() 
  36. human.walk() 
  37. whale = Whale() 
  38. whale.swim() 
  39. whale.walk() 

執行結果:

  1. Humans can swim 
  2. Humans can walk 
  3. Whales can swim 
  4. Whales can't walk 

事實上,子類鯨魚不應該依賴它不需要的接口 walk,針對這種情況,就需要對接口進行拆分,代碼如下:

  1. from abc import ABC, abstractmethod 
  2.  
  3. class Swimer(ABC): 
  4.  
  5.     @abstractmethod 
  6.     def swim(self) -> bool: 
  7.         pass 
  8.  
  9. class Walker(ABC): 
  10.     @abstractmethod 
  11.     def walk(self) -> bool: 
  12.         pass 
  13.  
  14.  
  15. class Human(Swimer,Walker): 
  16.     def swim(self)-> bool: 
  17.         print("Humans can swim"
  18.         return True 
  19.  
  20.     def walk(self)-> bool: 
  21.         print("Humans can walk"
  22.         return True 
  23.  
  24.  
  25. class Whale(Swimer): 
  26.  
  27.     def swim(self): 
  28.         print("Whales can swim"
  29.         return True 
  30.  
  31.  
  32. human = Human() 
  33. human.swim() 
  34. human.walk() 
  35. whale = Whale() 
  36. whale.swim() 

5、依賴反轉原則 (DIP)

依賴反轉原則的英文翻譯是 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。

我們將它翻譯成中文,大概意思就是:高層模塊不要依賴低層模塊。高層模塊和低層模塊應該通過抽象(abstractions)來互相依賴。除此之外,抽象不要依賴具體實現細節,具體實現細節依賴抽象。

在調用鏈上,調用者屬于高層,被調用者屬于低層,我們寫的代碼都屬于低層,由框架來調用。在平時的業務代碼開發中,高層模塊依賴低層模塊是沒有任何問題的,但是在框架層面設計的時候,就要考慮通用性,高層應該依賴抽象的接口,低層應該實現對應的接口。如下圖所示:

也就是說本來 ObjectA 依賴 ObjectB,但為了擴展后面可能會有 ObjectC,ObjectD,經常變化,因此為了頻繁改動,讓高層模塊依賴抽象的接口 interface,然后讓 ObjectB 也反過來依賴 interface,這就是依賴反轉原則。

舉個例子,wsgi 協議就是一種抽象接口,高層模塊有 uWSGI,gunicorn等,低層模塊有 Django,Flask 等,uWSGI,gunicorn 并不直接依賴 Django,Flask,而是通過 wsgi 協議進行互相依賴。

依賴倒置原則概念是高層次模塊不依賴于低層次模塊??此圃谝蟾邔哟文K,實際上是在規范低層次模塊的設計。低層次模塊提供的接口要足夠的抽象、通用,在設計時需要考慮高層次模塊的使用種類和場景。明明是高層次模塊要使用低層次模塊,對低層次模塊有依賴性。現在反而低層次模塊需要根據高層次模塊來設計,出現了「倒置」的顯現。

這樣設計好處有兩點:

  • 低層次模塊更加通用,適用性更廣
  • 高層次模塊沒有依賴低層次模塊的具體實現,方便低層次模塊的替換

最后的話

我去年(2020)年 2 月 3 號購買的《設計模式之美》專欄,將近一年半才把它學習完,再回看之前的代碼,真是一堆垃圾。之前一天寫完的代碼,重構差不多花了一個星期,重構之后,感覺還可以再重構的更好,似乎無止境,正如小爭哥說的那樣,項目無論大小,都可以有技術含量,所謂代碼細節是魔鬼,細節到處都存在在取舍,應該怎么樣,不應該怎么樣,都大有學問。

本文轉載自微信公眾號「Python七號」,可以通過以下二維碼關注。轉載本文請聯系Python七號公眾號。

 

責任編輯:武曉燕 來源: Python七號
相關推薦

2022-07-15 09:01:15

React對象編程

2020-03-31 21:50:41

JavaScript前端技術

2014-04-23 13:13:59

OpenShift

2009-06-02 10:02:50

eclipse jboeclipse jbojboss for e

2021-01-30 17:57:23

Python緩存開發

2022-05-31 08:49:02

Flutter應用程序前端

2024-09-04 01:30:14

2023-03-17 06:14:20

2023-03-17 07:13:43

2011-08-22 16:26:25

IOS開發Sqlite數據庫

2022-09-13 08:32:43

Ubuntu

2015-08-03 16:01:49

Ubuntu應用

2022-06-22 09:56:19

PythonMySQL數據庫

2021-07-09 12:37:31

GoPython編程語言

2012-08-21 09:42:24

設計架構設計原則

2013-05-22 09:59:10

HTML 5音頻

2009-07-28 08:39:56

Linux應用軟件Linux應用

2024-09-30 11:51:07

2010-02-03 09:45:34

Python目標

2025-01-21 15:20:14

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲免费观看视频 | 欧美性tv| 欧美日韩在线精品 | 国产一二三视频在线观看 | 亚洲精品视频在线看 | 免费亚洲一区二区 | 日韩a视频| 三级黄色大片网站 | 欧美亚洲国语精品一区二区 | 国产精品海角社区在线观看 | 91亚洲精品在线观看 | 国产精品2 | 91免费在线看 | 久久久久久免费观看 | 免费av毛片 | 亚洲欧美综合 | 日韩一区二区三区在线视频 | 国产男人的天堂 | 天天干夜夜拍 | 日韩久久网 | 国产一区2区 | 在线观看国产精品一区二区 | 国产1区2区在线观看 | 日韩精品成人 | 国内精品视频在线 | 欧美在线一区二区视频 | 久久国产精品-久久精品 | 七七婷婷婷婷精品国产 | 黄色网址在线播放 | 欧美综合一区二区 | 91久久精品一区二区二区 | 久久91av | 三级免费毛片 | 色婷婷综合久久久中字幕精品久久 | 五月免费视频 | 天天色影视综合 | 国产精品久久九九 | 日韩精品视频在线观看一区二区三区 | 天天操夜夜操 | 久久av一区二区三区 | 免费观看av网站 |