主頁 > 後端開發 > 一文了解函式設計的最佳實踐

一文了解函式設計的最佳實踐

2023-06-23 07:46:17 後端開發

1. 引言

良好設計的函式具有清晰的職責和邏輯結構,提供準確的命名和適當的引數控制,它們促進代碼復用、支持團隊協作,降低維護成本,并提供可測驗的代碼基礎,通過遵循最佳實踐,我們能夠撰寫出高質量、可讀性強的代碼,從而提高開發效率和軟體質量,下面我們將一一描述函式設計時能夠遵循的最佳實踐,

2. 遵循單一職責原則

遵循單一職責原則是函式設計的重要原則之一,它要求一個函式只負責完成單一的任務或功能,而不應該承擔過多的責任,

通過遵循該原則,我們設計出來的函式將具有以下幾個優點:

  1. 代碼可讀性的提高:函式只關注單一的任務或功能,使其邏輯更加清晰和簡潔,這樣的函式更易于閱讀和理解,能夠更快速地理解其作用和目的,提高代碼的可讀性,
  2. 函式復雜度的降低:單一職責的函式具有較小的代碼量和較少的依賴關系,這使得函式的邏輯更加集中和可控,減少了函式的復雜性,在維護和修改代碼時,由于函式的功能單一,我們可以更容易地定位和修復問題,降低了維護成本,
  3. 代碼可測驗性的提高:遵循單一職責原則的函式更容易進行單元測驗,因為函式的功能單一,我們可以更精確地定義輸入和期望輸出,撰寫針對性的測驗用例,這有助于提高代碼的可測驗性,確保函式的正確性和穩定性,

相對的,如果函式設計時沒有遵循單一職責原則,此時將帶來函式復雜性的增加,從而導致代碼可讀性的降低以及代碼可測驗性的下降,

下面是一個沒有遵循單一職責原則的函式與一個遵循該原則的函式的對比,首先是一個未遵循該原則的代碼示例:

func processData(data []int) {
    // 1. 驗證資料
    
    // 2. 清理資料
    
    // 3. 分析資料
    
    // 4. 保存資料
    
    // 5. 記錄日志
}

在上述示例中,processData 函式負責整個資料處理流程,包括驗證資料、清理資料、分析資料、保存資料和記錄日志,這個函式承擔了太多的職責,導致代碼邏輯復雜,可讀性不高,同時如果某一個節點需要變更,此時需要考慮是否對其他部分是否有影響,代碼的可維護性進一步降低,

下面我們將processData函式進行改造,使其遵循單一職責原則,從而凸顯出遵循單一職責原則的好處,代碼示例如下:

func processData(data []int) {
    // 1. 驗證邏輯拆分到calidateData函式中
    validateData(data)
    // 2. 清理資料 拆分到cleanData函式中
    cleanedData := cleanData(data)
    // 3. 分析資料 拆分到 analyzeData 函式中
    result := analyzeData(cleanedData)
    //4. 保存資料 拆分到 saveData 函式中
    saveData(result)
    //5. 記錄日志 拆分到 logData 函式中
    logData(result)
}

func validateData(data []int) {
    // 驗證資料的邏輯
    // ...
}

func cleanData(data []int) []int {
    // 清理資料的邏輯
    // ...
}

func analyzeData(data []int) string {
    // 分析資料的邏輯
    // ...
}

func saveData(result string) {
    // 保存資料的邏輯
    // ...
}

func logData(result string) {
    // 記錄日志的邏輯
    // ...
}

改造后的processData函式中,我們將不同的任務拆分到不同的函式中,每個函式只負責其中一部分功能,由于每個函式只需要專注于其中一項任務,代碼的可讀性更好,而且每個函式只負責其中一部分功能,故代碼的復雜性也明顯降低了,而且代碼也更容易測驗了,

而且由于此時每個函式只負責其中一個任務,如果其存在變更,也不會擔心影響到其他部分的內容,代碼的可維護性也更高了,

通過對比這兩個示例,我們可以很清楚得看到,遵循單一職責函式的函式,其代碼可讀性更高,復雜度更低,代碼可測驗性更強,同時也提高了代碼的可維護性,

3. 控制函式引數數量

函式在不斷進行迭代程序中,函式引數往往會不斷增多,此時我們在每次迭代程序中,都需要思考函式引數是否過多,通過避免函式引數過多,這能夠給我們一些好處:

  1. 首先是函式更加容易使用,過多的引數會增加函式的復雜性,使函式呼叫時的意圖不夠清晰,通過控制引數數量,可以使函式的呼叫更加簡潔和方便,
  2. 其次是函式的耦合度的降低: 過多的引數會增加函式與呼叫者之間的耦合度,使函式的可復用性和靈活性降低,通過封裝相關引數為物件或結構體,可以減少引數的數量,從而降低函式之間的依賴關系,提高代碼的靈活性和可維護性,
  3. 同時也提高了函式的擴展性,當需要對函式進行功能擴展時,過多的引數會使函式的修改變得復雜,可能需要修改大量的呼叫代碼,而通過封裝相關引數,只需修改封裝物件或結構體的定義,可以更方便地擴展函式的功能,同時對現有的呼叫代碼影響較小,
  4. 能夠及時識別函式是否符合單一職責原則,當函式引數過多時,同時我們又無法將其抽取為一個結構體引數,這往往意味著函式的職責不單一,從另外一個方面,迫使我們在函式還沒有堆積更多功能前,及時將其拆分為多個函式,提高代碼的可維護性,

下面,我們通過一個代碼示例,展示一個函式引數數量過多的例子和優化后的示例,首先是優化前的函式代碼示例:

func processOrder(orderID string, customerName string, customerEmail string, shippingAddress string, billingAddress string, paymentMethod string, items []string) {
    // 處理訂單的邏輯
    // ...
}

在這個示例中,函式 processOrder 的引數數量較多,包括訂單ID、顧客姓名、顧客郵箱、識訓地址、賬單地址、支付方式和商品串列等,呼叫該函式時,需要傳遞大量的引數,使函式呼叫變得冗長且難以閱讀,

下面,我們將processOrder的引數抽取成一個結構體,控制函式引數的數量,代碼示例如下:

type Order struct {
    ID               string
    CustomerName     string
    CustomerEmail    string
    ShippingAddress  string
    BillingAddress   string
    PaymentMethod    string
    Items            []string
}

func processOrder(order Order) {
    // 處理訂單的邏輯
    // ...
}

在優化后的示例中,我們將相關的訂單資訊封裝為一個 Order 結構體,通過將引數封裝為結構體,函式的引數數量大大減少,只需傳遞一個結構體物件即可,

這樣的設計使函式呼叫更加簡潔和易于理解,同時也提高了代碼的可讀性和可維護性,如果需要添加或修改訂單資訊的欄位,只需修改結構體定義,而不需要修改呼叫該函式的代碼,提高了代碼的擴展性和靈活性,

其次,在processOrder函式引數抽取的程序中,如果發現無法將函式引數抽取為結構體的話,也能幫助我們及時識別到函式職責不單一的問題,從而能夠及時將函式進行拆分,提高代碼的可維護性,

因此,在函式設計迭代程序中,控制函式引數過多是非常有必要的,能夠提高函式的可用性和擴展性,其次也能夠幫助我們識別函式是否滿足符合單一職責原則,也間接提高了代碼的可維護性,

4. 函式命名要準確

函式設計時,適當的函式命名是至關重要的,它能夠準確、清晰地描述函式的功能和作用,一個好的函式名能夠使代碼易于理解和使用,提高代碼的可讀性和可維護性,

相對準確的函式命名,能夠明確傳達函式的用途和功能,避免其他人對函式的誤用,同時,也提高了代碼的可讀性,其他人閱讀代碼時,能夠更加輕松得理解函式的含義和邏輯,因此,設計函式時,一個清晰準確的函式名也是至關重要的,

下面再通過一個代碼的例子,展示準確清晰的函式命名,和一個含糊不清的函式命名之間的區別:

// 不合適的函式命名示例
func F(a, b int) int {
    // 函式體的邏輯
    // ...
}

// 適當的函式命名示例
func Add(a, b int) int {
    // 將兩個數相加
    return a + b
}

在上述示例中,第一個函式命名為 F,沒有提供足夠的資訊來描述函式的功能和用途,這樣的函式命名使其他人難以理解函式的目的和作用,

而在第二個函式中,我們將函式命名為 Add,清晰地描述了函式的功能,即將兩個數相加,這樣的命名使得代碼更易于理解和使用,

因此,在函式設計中,我們需要定義一個清晰和準確的函式命名,這樣能夠提高代碼的可讀性,讓其他人更容易理解我們的意圖,

5. 控制函式長度

在函式撰寫和迭代程序中,一個超過1000行的函式,一般不是一開始實作便是如此,而是在不斷迭代程序中,不斷往其中迭代功能,才最終出現了這個大函式,由此造成的后果,各種業務邏輯在該函式中錯綜復雜,接手的同事往往難以快速理解其功能和行為,而且,在功能迭代程序中,由于各種邏輯穿插其中,此時函式將變得難以修改和維護,代碼基本不具有可讀性和可維護性,

因此,在代碼迭代程序中,時時考慮函式的長度是至關重要的,當在迭代程序中,發現函式已經過長了,此時應該盡快通過一些手段重構該函式,避免函式最終無法維護,下面是一些可能的手段:

  1. 確保函式只負責完成單一的任務或功能,避免函式承擔過多的責任,
  2. 當函式過長時,將其拆分為多個較小的函式,每個函式負責特定的功能或操作,
  3. 將長函式中的某些邏輯提取出來,形成獨立的輔助函式,以減少函式的長度和復雜度,

在需求迭代程序中,我們時時關注函式的長度,當長度過長時,便適當進行重構,保持代碼的可讀性和可維護性,

6. 進行防御式編程

在函式撰寫程序中,盡量考慮各種可能的錯誤和例外情況,以及相應的處理策略,這能夠帶來一些好處:

  1. 增強程式的健壯性: 防御式編程通過對可能的錯誤和例外情況進行處理,它可以幫助程式更好地處理無效的輸入、邊界條件和例外情況,從而提高程式的健壯性和可靠性,
  2. 減少程式的崩潰和故障: 通過合理的錯誤處理和例外處理機制,防御式編程可以防止程式在出現錯誤時崩潰或產生不可預測的行為,它可以使程式在遇到問題時能夠適當地處理和恢復,從而減少系統的故障和崩潰,

下面是一個對比的示例代碼,展示一個進行防御式編程的代碼和一個未進行防御式編程的代碼示例:

// 沒有防御編程的函式示例
func Divide(a, b int) int {
    return a / b
}

// 有防御編程的函式示例
func SafeDivide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

在上述示例中,第一個函式 Divide 沒有進行錯誤處理,如果除數 b 為零,會導致運行時發生除以零的錯誤,可能導致程式例外終止,而第二個函式 SafeDivide 在執行除法之前,先進行了錯誤檢查,如果除數 b 為零,則回傳一個自定義的錯誤,避免了程式崩潰,

因此,我們在函式撰寫程序中,盡量考慮各種可能的錯誤和例外情況,對其進行處理,保證函式的健壯性,

7. 總結

在這篇文章中,我們總結了幾個函式設計的最佳實踐,如遵循單一職責原則,控制函式引數數量,函式命名要清晰準確等,通過遵循這些原則,能夠讓我們設計出來高質量、可讀性強的代碼,同時也具有更強的可維護性,

但是也需要注意的是,函式一開始設計時總是相對比較完美的,只是在不斷迭代中,不斷堆積代碼,最終代碼冗長,復雜,各種邏輯穿插其中,使得維護起來越發困難,因此,我們更多的應該是在迭代程序中,多考慮函式設計是否違反了我們這里提出的原則,能在一開始就識別到代碼的壞味道,從而避免最終演變成難以維護和迭代的函式,

基于此,我們完成了對函式設計最佳實踐的介紹,希望對你有所幫助,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555821.html

標籤:其他

上一篇:一文了解函式設計的最佳實踐

下一篇:返回列表

標籤雲
其他(161494) Python(38244) JavaScript(25512) Java(18251) C(15238) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7265) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1971) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 一文了解函式設計的最佳實踐

    # 1. 引言 良好設計的函式具有清晰的職責和邏輯結構,提供準確的命名和適當的引數控制。它們促進代碼復用、支持團隊協作,降低維護成本,并提供可測驗的代碼基礎。通過遵循最佳實踐,我們能夠撰寫出高質量、可讀性強的代碼,從而提高開發效率和軟體質量。下面我們將一一描述函式設計時能夠遵循的最佳實踐。 # 2. ......

    uj5u.com 2023-06-23 07:46:17 more
  • 一文了解函式設計的最佳實踐

    # 1. 引言 良好設計的函式具有清晰的職責和邏輯結構,提供準確的命名和適當的引數控制。它們促進代碼復用、支持團隊協作,降低維護成本,并提供可測驗的代碼基礎。通過遵循最佳實踐,我們能夠撰寫出高質量、可讀性強的代碼,從而提高開發效率和軟體質量。下面我們將一一描述函式設計時能夠遵循的最佳實踐。 # 2. ......

    uj5u.com 2023-06-23 07:45:11 more
  • 一文了解Go語言的函式

    # 1. 引言 函式是編程中不可或缺的組成部分,無論是在`Go`語言還是其他編程語言中,函式都扮演著重要的角色。函式能夠將一系列的操作封裝在一起,使得代碼更加模塊化、可重用和易于維護。 在本文中,我們將詳細介紹Go語言中函式的概念和使用方法,包括函式的定義、引數和回傳值、呼叫方式、可變引數、函式作為 ......

    uj5u.com 2023-06-22 07:42:11 more
  • celery筆記五之訊息佇列的介紹

    > 本文首發于公眾號:Hunter后端 > 原文鏈接:[celery筆記五之訊息佇列的介紹](https://mp.weixin.qq.com/s/fw7b1Gha0XpTYuCg3aZcWA) 前面我們介紹過 task 的處理方式,將 task 發送到佇列 queue,然后 worker 從 qu ......

    uj5u.com 2023-06-22 07:42:04 more
  • C++面試八股文:用過STL嗎?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第21面: > 面試官:用過STL嗎? > > 二師兄:(每天都用好嗎。。)用過一些。 > > 面試官:你知道STL是什么? > > 二師兄:STL是指標準模板庫(`Standard Template Library`),是C++區別于C語言的特征之 ......

    uj5u.com 2023-06-22 07:41:59 more
  • Scala泛型

    # 泛型的定義 ```Scala object _11_泛型 { def main(args: Array[String]): Unit = { //[A] 這個代表的就是泛型 ==》 在創建物件的時候,可以指定需要傳進去的型別 //作用就是在創建物件的時候,可以對傳進去的引數一個約束,當設定泛型位 ......

    uj5u.com 2023-06-22 07:41:54 more
  • 現代C++學習指南-具體類

    > 類作為C++中重要的概念之一,有著眾多的特性,也是最迷人的部分! 類是一個加工廠,開發者使用C++提供的各種材料組裝這個工廠,使得它可以生產出符合自己要求的資料,通過對工廠的改造,可以精細控制物件從出生到死亡的各種行為,真正達到我的代碼我做主的境界。 ### 類 我們經常說的面向物件三大特征:封 ......

    uj5u.com 2023-06-22 07:41:49 more
  • 【python基礎】類-模塊

    隨著不斷給類添加功能,檔案可能變得很長,即便妥善地使用了繼承亦是如此,為遵循Python的總體理念,應讓檔案盡可能簡潔。為在這方面提供幫助,Python允許將類存盤在模塊中,然后在主程式中匯入所需的模塊。 # 1.匯入單個類 新建一個Animal類的模塊,其中只包含Animal類,撰寫程式如下所示: ......

    uj5u.com 2023-06-22 07:41:39 more
  • 54基于java的高校圖書館座位預約系統設計與實作

    基于java的座位預約系統,可以用于圖書館占位系統,圖書館座位預約系統,大學自習室占座系統,自習室座位預約系統,圖書館預約占座系統,自習室預約占座系統,高校圖書館座位預約系統等等; ......

    uj5u.com 2023-06-22 07:41:06 more
  • 【python基礎】類-繼承

    撰寫類時,并非總是要從空白開始。如果要撰寫的類時另一個現成類的特殊版本,可使用繼承。一個類繼承另一個類時,它將自動獲得另一個類的所有屬性和方法 原有的類稱為父類,而新類被稱為子類。子類繼承了其父類的所有屬性和方法,同時還可以定義自己的屬性和方法。 繼承語法格式: class 子類名(父類名): # ......

    uj5u.com 2023-06-22 07:40:41 more