設計模式六大原則2-里氏替換原則

肯定有不少人跟我剛看到這項原則的時候一樣,對這個原則的名字充滿疑惑。其實原因就是這項原則最早是在1988年,由麻省理工學院的一位姓里的女士(Barbara Liskov)提出來的。

定義1:如果對每一個類型為 T1的對象 o1,都有類型為 T2 的對象o2,使得以 T1定義的所有程序 P 在所有的對象 o1 都代換成 o2 時,程序 P 的行為沒有發生變化,那么類型 T2 是類型 T1 的子類型。

定義2:所有引用基類的地方必須能透明地使用其子類的對象。

問題由來:有一功能P1,由類A完成。現需要將功能P1進行擴展,擴展后的功能為P,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來完成,則子類B在完成新功能P2的同時,有可能會導致原有功能P1發生故障。

解決方案:當使用繼承時,遵循里氏替換原則。類B繼承類A時,除添加新的方法完成新增功能P2外,盡量不要重寫父類A的方法,也盡量不要重載父類A的方法。

繼承包含這樣一層含義:父類中凡是已經實現好的方法(相對于抽象方法而言),實際上是在設定一系列的規范和契約,雖然它不強制要求所有的子類必須遵從這些契約,但是如果子類對這些非抽象方法任意修改,就會對整個繼承體系造成破壞。而里氏替換原則就是表達了這一層含義。

繼承作為面向對象三大特性之一,在給程序設計帶來巨大便利的同時,也帶來了弊端。比如使用繼承會給程序帶來侵入性,程序的可移植性降低,增加了對象間的耦合性,如果一個類被其他的類所繼承,則當這個類需要修改時,必須考慮到所有的子類,并且父類修改后,所有涉及到子類的功能都有可能會產生故障。

舉例說明繼承的風險,我們需要完成一個兩數相減的功能,由類A來負責。

class A{  public int func1(int a, int b){  return a-b;  }  
}  public class Client{  public static void main(String[] args){  A a = new A();  System.out.println("100-50="+a.func1(100, 50));  System.out.println("100-80="+a.func1(100, 80));  }  
}

運行結果:

100-50=50
100-80=20

后來,我們需要增加一個新的功能:完成兩數相加,然后再與100求和,由類B來負責。即類B需要完成兩個功能:

  • 兩數相減
  • 兩數相加,然后再加100

由于類A已經實現了第一個功能,所以類B繼承類A后,只需要再完成第二個功能就可以了,代碼如下:

class B extends A{  public int func1(int a, int b){  return a+b;  }  public int func2(int a, int b){  return func1(a,b)+100;  }  
}  public class Client{  public static void main(String[] args){  B b = new B();  System.out.println("100-50="+b.func1(100, 50));  System.out.println("100-80="+b.func1(100, 80));  System.out.println("100+20+100="+b.func2(100, 20));  }  
}  

類B完成后,運行結果:

100-50=150
100-80=180
100+20+100=220

我們發現原本運行正常的相減功能發生了錯誤。原因就是類B在給方法起名時無意中重寫了父類的方法,造成所有運行相減功能的代碼全部調用了類B重寫后的方法,造成原本運行正常的功能出現了錯誤。在本例中,引用基類A完成的功能,換成子類B之后,發生了異常。在實際編程中,我們常常會通過重寫父類的方法來完成新的功能,這樣寫起來雖然簡單,但是整個繼承體系的可復用性會比較差,特別是運用多態比較頻繁時,程序運行出錯的幾率非常大。如果非要重寫父類的方法,比較通用的做法是:原來的父類和子類都繼承一個更通俗的基類,原有的繼承關系去掉,采用依賴、聚合,組合等關系代替。

里氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。它包含以下4層含義:

  • 子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。
  • 子類中可以增加自己特有的方法。
  • 當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬松。
  • 當子類的方法實現父類的抽象方法時,方法的后置條件(即方法的返回值)要比父類更嚴格。

看上去很不可思議,因為我們會發現在自己編程中常常會違反里氏替換原則,程序照樣跑的好好的。所以大家都會產生這樣的疑問,假如我非要不遵循里氏替換原則會有什么后果?

后果就是:你寫的代碼出問題的幾率將會大大增加。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95423.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95423.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Security 深度學習(五): 過濾器鏈與自定義過濾器

目錄1. 引言:揭開Spring Security的內部奧秘2. Spring Security 過濾器鏈核心機制2.1 DelegatingFilterProxy:整合Spring與Servlet容器2.2 FilterChainProxy:管理安全過濾器鏈的“總管”2.3 Security Filters:核心安全功能的承載者…

微軟GraphRAG 端到端使用及自用工具類

文章目錄一. 環境準備1.安裝 Python 環境2.安裝依賴3.配置 LLM API Key二. 初始化項目三. 文檔上傳 & 索引構建四. 問答(CLI 方式)示例:五. 代碼中調用 GraphRAG工具概覽核心工具詳解1. simple_graphrag_integration.py - 智能問答核心2.…

sqlserver2008導入excel表數據遇到的問題

1.如果表格為.xlsx格式時可能會提示“沒有為此鏈接管理提供列”,無法點擊下一步的話,建議可以使用.csv格式 .csv格式可能也會存在此提示,但是可以不用管 2.導入.csv數據時,字段為int時,填null導入不進去的話可以給個0作…

Unity游戲打包——打包流程

本文由 NRatel 歷史筆記整理而來,如有錯誤歡迎指正。一、基本流程二、組合步驟把上述每步做成獨立的輸入輸出邏輯 y fuc(x)然后,控制/組合其過程,可靈活產生不同的流程:1、單渠道出測試包2、單渠道出正式包3、單渠道包熱更三、構…

卷積神經網絡(二):手寫數字識別項目(一)

文章目錄手寫數字識別項目一、準備數據集二、定義模型三、模型訓練3.1 導入依賴庫3.2 設備設置(CPU/GPU 自動選擇)3.3 超參數定義3.4數據集準備1.獲取數據集2.劃分訓練集與驗證集3.創建 DataLoader(按批次加載數據)3.5模型初始化與…

批量給文件夾添加文件v2【件批量復制工具】

代碼功能介紹 這個代碼的功能就是一個,給某個文件夾里面添加某個文件(含父級文件夾下的每一個子文件夾) 舉個例子,父級文件夾是:“D:\Desktop\1,要添加的文件路徑是:D:\1.txt” 則最后會把文件…

Qt實現2048小游戲:看看AI如何評估棋盤策略實現“人機合一

2048 是一款經典的數字益智游戲,其簡單的規則背后蘊含著豐富的策略性。該項目不僅完整實現了 2048 的核心玩法,還包含了一個基于啟發式評估和蒙特卡洛方法的智能 AI 玩家。 我們將從項目整體架構入手,逐一解析游戲核心邏輯、UI 渲染、事件處理、AI 策略等關鍵模塊,并通過展…

封裝紅黑樹實現mysetmymap

1. 源碼分析 set實例化rb_tree時第二個模板參數給的是key&#xff0c;map實例化rb_tree時第?個模板參數給的是 pair<const key,T>&#xff0c;這樣一顆紅黑樹既可以實現key搜索場景的set&#xff0c;也可以實現key/value搜索場 景的map源碼里面模板參數是用T代表value&…

以OWTB為核心以客戶為基礎的三方倉運配一體化平臺分析V0.2

一、系統概述以OWTB&#xff08;Order-Warehouse-Transportation-Billing&#xff0c;訂單-倉儲-運輸-結算&#xff09;為核心的三方倉運配一體化平臺&#xff0c;是專為第三方物流企業打造的深度定制化解決方案。該平臺以第三方倉運配為主線&#xff0c;以多客戶/多SKU/個性化…

技術框架之腳手架實現

一、 序言在日常的企業級Java開發中&#xff0c;我們經常會發現自己在重復地做著一些項目初始化工作&#xff1a;創建相似的項目結構、引入一堆固定的依賴包、編寫通用的配置文件、拷貝那些幾乎每個項目都有的基礎工具類和日志配置。這些工作不僅枯燥乏味&#xff0c;而且容易出…

小迪安全v2023學習筆記(七十七講)—— 業務設計篇隱私合規檢測重定向漏洞資源拒絕服務

文章目錄前記WEB攻防——第七十七天業務設計篇&隱私合規檢測&URL重定向&資源拒絕服務&配合項目隱私合規 - 判斷規則&檢測項目介紹案例演示URL重定向 - 檢測判斷&釣魚配合介紹黑盒測試看業務功能看參數名goole語法搜索白盒測試跳轉URL繞過思路釣魚配合資…

用AI做旅游攻略,真能比人肉整理靠譜?

大家好&#xff0c;我是極客團長&#xff01; 作為一個沉迷研究 “AI 工具怎么滲透日常生活” 的科技博主&#xff0c;我開了個 AI 解決生活小事系列。 前兩期聊了用 AI 寫新聞博客、扒商業報告&#xff0c;后臺一堆人催更&#xff1a;能不能搞點接地氣的&#xff1f;比如&am…

Axure RP 9 Mac 交互原型設計

原文地址&#xff1a;Axure RP 9 Mac 交互原型設計 安裝教程 Axure RP 9是一款功能強大的原型設計和協作工具。 它不僅能夠幫助用戶快速創建出高質量的原型設計&#xff0c;還能促進團隊成員之間的有效協作&#xff0c;從而極大地提高數字產品開發的效率和質量。 擁有直觀易…

多線程——線程狀態

目錄 1.線程的狀態 1.1 NEW 1.2 RUNNABLE 1.3 BLOCKED 1.4 WAITING 1.5 TIMED_WAITING 1.6 TERMINATED 2.線程狀態的相互轉換 在上期的學習中&#xff0c;已經理解線程的啟動&#xff08;start()&#xff09;、休眠&#xff08;sleep()&#xff09;、中斷&#xff08;i…

IMX6ULL的設備樹文件簡析

先分析一個完整的設備樹&#xff0c;是怎么表達各種外設信息的。以imux6ull開發板為例進行說明。這個文件里就一個設備信息才這么點內容&#xff0c;是不是出問題了&#xff1f;當然不是&#xff0c;我們知道dts文件是可包含的&#xff0c;所以&#xff0c;最終形成的一個完整文…

【ARM】PACK包管理

1、 文檔目標對 pack 包的管理有更多的了解。2、 問題場景客戶在安裝了過多的 pack 包導致軟件打開比較慢&#xff0c;各種 pack 包顏色的區別&#xff0c;及圖標不同。3、軟硬件環境1&#xff09;、軟件版本&#xff1a;Keil MDK 5.392&#xff09;、電腦環境&#xff1a;Wind…

【Kubernetes】知識點4

36. 說明K8s中Pod級別的Graceful Shutdown。答&#xff1a;Graceful Shutdown&#xff08;優雅關閉&#xff09;是指當 Pod 需要終止時&#xff0c;系統給予運行中的容器一定的時間來等待業務的應用的正常關閉&#xff08;如保存數據、關閉連接、釋放資源等&#xff09;&#x…

Paraverse平行云實時云渲染助力第82屆威尼斯電影節XR沉浸式體驗

今年&#xff0c;Paraverse平行云實時云渲染平臺LarkXR&#xff0c;為享有盛譽的第82屆威尼斯國際電影節&#xff08;8月27日至9月6日&#xff09;帶來沉浸式體驗。 LarkXR助力我們的生態伙伴FRENCH TOUCH FACTORY&#xff0c;實現ITHACA容積視頻的XR交互演示&#xff0c;從意大…

大數據開發計劃表(實際版)

太好了&#xff01;我將為你生成一份可打印的PDF版學習計劃表&#xff0c;并附上項目模板與架構圖示例&#xff0c;幫助你更直觀地執行計劃。 由于當前環境無法直接生成和發送文件&#xff0c;我將以文本格式為你完整呈現&#xff0c;你可以輕松復制到Word或Markdown中&#xf…

GitLab 18.3 正式發布,更新多項 DevOps、CI/CD 功能【二】

沿襲我們的月度發布傳統&#xff0c;極狐GitLab 發布了 18.3 版本&#xff0c;該版本帶來了通過直接轉移進行遷移、CI/CD 作業令牌的細粒度權限控制、自定義管理員角色、Kubernetes 1.33 支持、通過 API 讓流水線執行策略訪問 CI/CD 配置等幾十個重點功能的改進。下面是對部分重…