《架構整潔之道》學習筆記 Part 2 編程範式

来源:https://www.cnblogs.com/tengzijian/archive/2023/07/16/17557427.html
-Advertisement-
Play Games

電腦編程發展至今,一共只有三個編程範式: - 結構化編程 - 面向對象編程 - 函數式編程 ### 編程範式和軟體架構的關係 - 結構化編程是各個模塊的演算法實現基礎 - 多態(面向對象編程)是跨越架構邊界的手段 - 函數式編程是規範和限制數據存放位置與訪問許可權的手段 **軟體架構的三大關註重點** ...


電腦編程發展至今,一共只有三個編程範式:

  • 結構化編程
  • 面向對象編程
  • 函數式編程

編程範式和軟體架構的關係

  • 結構化編程是各個模塊的演算法實現基礎
  • 多態(面向對象編程)是跨越架構邊界的手段
  • 函數式編程是規範和限制數據存放位置與訪問許可權的手段

軟體架構的三大關註重點功能性組建獨立性以及數據管理,和編程範式不謀而合

結構化編程

限制控制權的直接轉移,禁止 goto,用 if/else/while 替代

  • Dijkstra 發現:goto 語句的某些用法會導致模塊無法被遞歸拆分成更小的、可證明的單元,這會導致無法採用分解法將大型問題進一步拆分成更小的、可證明的部分。
  • Bohm 和 Jocopini 證明瞭:可以用順序結構、分支結構、迴圈結構構造出任何程式
  • 測試只能證明 Bug 的存在,並不能證明不存在 Bug
  • 結構化編程範式的價值:賦於我們構建可證偽程式單元的能力。如果測試無法證偽這些函數,就可以認為這些函數足夠正確
  • 在架構設計領域,功能性降解拆分仍然是最佳實踐之一

面向對象編程

限制控制權的間接轉移,禁用函數指針,用多態替代

什麼是面向對象?
  • 數據與函數的組合?
    • o.f() 和 f(o) 沒有區別
  • 對真實世界進行建模的方式?
    • 到底如何進行?為什麼這麼做?有什麼好處?
    • 面向對象編程究竟是什麼?
  • 封裝、繼承、多態?
    • 面向對象編程語言必須支持這三個特性
封裝

把一組關聯的數據和函數管理起來,外部只能看見部分函數,數據則完全不可見。

封裝並不是面向對象語言特有的,C 語言也支持:

point.h

struct Point;
struct Point* makePoint(double x, double y);
double distance(struct Point *p1, struct Point *p2)

C 語言的封裝是完美的封裝:利用 forward declaration,Point 的數據結構、內部實現對 point.h 的使用者完全不可見。

而後來的 C++ 雖然是面向對象的編程語言,但卻破壞了封裝性:

point.h

class Point {
public:
    Point(double x, double y);
    double distance(const Point& p1, const Point& p2);
    
private:
    double sqrt(double x);
private:
    double x;
    double y;
};

C++ 編譯器需要知道類的對象大小,因此必須在頭文件中看到成員變數的定義。雖然 private 限制了使用者訪問私有成員,但這樣仍然暴露了類的內部實現。(C++ 的 PIMPL 慣用法可以在一定程度上緩解這個問題)

Java 和 C# 拋棄了頭文件、實現分離的編程方式,進一步削弱了封裝性,因為無法區分類的聲明和定義。

繼承

C 語言也支持繼承:

namedPoint.h

struct NamedPoint;
struct NamedPoint* makeNamedPoint(double x, double y, char* name);
void setName(struct NamePoint *np, char* name);
char* getName(struct NamedPoint *np);

namedPoint.c

#include "namePoint.h"

struct NamedPoint {
    double x;
    double y;
    char* name;
};

// 或者
#include "point.h"

struct NamePoint {
    Point parent_;
    char* name;
};

// 省略其他函數實現

main.c

#include "point.h"
#include "namedPoint.h"

int main() {
    struct NamePoint* p1 = makeNamedPoint(0.0, 0.0, "origin");
    struct NamePoint* p2 = mameNamePoint(1.0, 1.0, "upperRight");
    // C 語言中的繼承需要強制轉換 p1、p2 的類型
    // 真正的面向對象語言一般可以自動將子類轉成父類指針/引用
    distance((struct Point*)p1, (struct Point*)p2);
}

在 main.c 中,NamePoint 被當作 Point 來使用。之所以可以,是因為 NamePoint 是 Point 的超集,且共同成員的順序一致。C++ 中也是這樣實現單繼承的。

多態

在面向對象語言發明之前,C 語言也支持多態。

UNIX 要求每個 IO 設備都提供 open、close、read、write、seek 這 5 個標準函數:

struct FILE {
    void (*open)(char* name, int mode);
    void (*close)();
    int (*read)();
    void (*write)(char);
    void (*seek)(long index, int mode);
};

這裡的 FILE 就相當於一個介面類,不同的 IO 設備有各自的實現函數,通過設置函數指針指向不同的實現來達到多態的目的。上層的功能邏輯只依賴 FILE 結構體中的 5 個標準函數,並不關心具體的 IO 設備什麼。更換 IO 設備也無需修改功能邏輯的代碼,IO 只是功能邏輯的一個插件

C++ 中每個虛函數的地址都記錄在一個叫 vtable 的數據結構中,帶有虛函數的類會有一個隱式的、指向 vtable 的虛表指針。每次調用虛函數都會先查詢 vtable,子類構造函數負責將子類虛函數地址載入到對象的 vtable 中。

多態本質上就是函數指針的一種應用。用函數指針實現多態的問題在於函數指針的危險性。依賴人為遵守一系列的約定很容易產生難以跟蹤和調試的 bug。面向對象編程使得多態再不需要依賴人工遵守約定,可以更簡單、更安全地實現複雜功能。面向對象編程的出現使得“插件式架構”普及開來。

此外,面向對象編程的帶來的另一個重大好處是依賴反轉:通過引入介面,源碼的依賴關係不再受到控制流的限制,軟體架構師可以輕易地更改源碼的依賴關係。這也是面向對象編程範式的核心本質(關於依賴反轉,後面會單獨用一篇來介紹)。

回到開始的問題,面向對象到底什麼?有許多不同的說法和意見,但是對於軟體架構師來說,面向對象編程就是以多態為手段,控制源碼依賴的能力。這種能力可以讓軟體架構師構建某種插件式架構,讓高層策略和底層實現組件相分離,底層組件作為插件可以獨立開發和部署。

函數式編程

限制賦值操作

  • 函數式編程中的變數不可變

  • 不可變性是軟體架構需要考慮的重點,因為所有的併發、死鎖、競爭問題都是可變變數導致的,如果變數不可變,就不會有這些問題

  • 架構設計良好的程式應該拆分成可變不可變兩種組件,其中可變狀態組件中的邏輯越少越好

  • 事件溯源:只存儲事務記錄,不存儲具體狀態;需要狀態時,從頭計算所有事務。

    • 例如銀行程式只保存每次的交易記錄,不保存用戶餘額,每次查詢餘額時,將全部交易記錄取出累計
    • 這種模式只需要 CR (Create & Retrieve),不需要 UD (Update & Delete),沒有了更新和刪除操作,自然也不存在併發問題
    • 缺點:對存儲和處理能力要求較高(但隨著技術的發展,這方面將越來越不成問題)
    • 應用:git

總結

從 1946 年圖靈寫下第一行代碼至今,軟體編程的核心沒有變:電腦程式無一例外是由順序結構、分支結構、迴圈結構和間接轉移這幾種行為組合而成的,無可增加, 也缺一不可。

所有三個範式都是限制了編碼方式,而不是增加新能力

  • 結構化編程:限制控制權的直接轉移,禁止 goto,用 if/else/while 替代
  • 面向對象編程:限制控制權的間接轉移,禁用函數指針,用多態替代
  • 函數式編程:限制賦值操作

三個編程範式都是在 1958 - 1968 年間提出,此後再也沒有新的範式提出,未來幾乎不可能再有新的範式。因為除了 goto 語句、函數指針、賦值語句之外,也沒有什麼可以限制的了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # shell腳本-lnmp一鍵部署 創建文件lnmp.sh ``` vim lnmp.sh ``` ``` #!/bin/bash #描述:LNMP網站架構部署腳本 cat /dev/null echo "創建Nginx運行用戶" groupadd www useradd -g www www - ...
  • # shell腳本-MySQL資料庫備份 ## 準備: 確保mysql服務啟動 **可以通過mysqldump命令來備份資料庫** 1.mysqldump 命令語法: 使用 mysqldump 命令備份一個資料庫的語法格式如下: ``` mysqldump -u username -p dbpass ...
  • # 一. 索引概述 ## 1. 介紹 **索引是幫助MySQL高效獲取數據的數據結構(有序)。在數據之外,資料庫系統還維護著滿足特定查找演算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找演算法,這種數據結構就是索引。** ![](https://tcs-de ...
  • 原文地址:https://blog.csdn.net/zhanglei5415/article/details/131434931 ## 一、問題 當對含有中文的url字元串,進行NSURL對象包裝時,是不能被識別的。 不會得到期望的NSURL對象,而是返回一個nil 值 ; ```objectiv ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • 今天接到粉絲私信,詢問是否可以通過Canvas繪製一些圖形,然後根據粉絲提供的模板圖,通過Canvas進行模擬繪製,通過分析發現,圖形雖然相對簡單,但是如果不藉助相應的軟體,純代碼繪製還是稍微費些時間。今天將繪製圖形源碼分享出來,僅供學習分享之用,如有不足之處,還請指正。 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202307/3076680-20230713141300146-1450511408.png) # 1. 水平擴展 ## 1.1. 有助於提高系統的整體容量和韌性 ## 1.2. 現階段構建的幾乎所有系統,都 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...