面向對象五大設計原則

最近在看七牛云許式偉的架構課,?重溫了面向對象五大設計原則(SOLID),扣理論文字找出處。(當然許老板是不可能深聊這么低級的內容,🤡)

注意區分設計原則和設計模式。
設計原則更為抽象和泛化;
設計模式也是抽象或泛化的良好實踐,但是它們提供了更具體和實用的底層建議。

面向對象5大設計原則
Single Responsiblity Principle單一職責原則
Open/Closed Principle開閉原則
Likov Substitution Principle里斯替代原則
Interface Segregation Principle接口隔離原則
Dependency inversion依賴倒置原則

單一職責原則

只能有一個讓組件或類發生改變的原因;或者說每個組件或類專注于單一功能,解決特定問題。

there should never be more than one reason for a class to change. A class should be focused on a single functionality, address a specific concern.

開閉原則

對擴展開放, 對修改封閉。

擴展類的幾種方式:

  • ??從類繼承

  • ??類中重寫同名行為

  • ??擴展類的某些行為

一般我們通過繼承或者實現接口來實踐開閉原則。

class?Person{public?int?age;public?string?name;public?Person(string?name,?int?age){this.name?=?name;this.age?=?age;}public?virtual?void?SayHallo(){Console.WriteLine("我是{0},今年{1}",?name,?age);}}class?Student?:?Person{public?string?major;public?Student(string?name,?int?age,?string?major)?:?base(name,?age){this.major?=?major;}public?override?void?SayHallo()???//子類中override重寫,實現虛方法{Console.WriteLine("我是{0},今年{1},正在學習{2}",?name,?age,?major);}}class?Program{static?void?Main(string[]?args){Person?trevor1?=?new?Person("Trevor",?18);trevor1.SayHallo();Student?trevor2?=?new?Student("Trevor",?18,"C#");trevor2.SayHallo();}}output:
我是Trevor,今年18
我是Trevor,今年18,正在學習C#

里氏替代原則

在父子類生態中,在父類出現的地方,可以用子類對象替換父類對象,同時不改變程序的功能和正確性。

。。?乍一看,這不是理所當然嗎?

為啥單獨拎出來鞭尸,鞭策。

比如上例我們使用

Person?trevor1?=?new?Student("trevor",18,"C#")??//?子類對象替換父類對象trevor1.SayHello();

利用多態正確表達了含義。


但是某些情況下濫用繼承,卻不一定保證程序的正確性,會對使用者造成誤解。

比如下面經典的[矩形-正方形求面積]反例:

public?class?Rectangle
{//?分別設置寬高public?virtual?double?Width?{get;set;}public?virtual?double?Height?{get;set;}public?virtual?void?Area(){Console.WriteLine("面積是:"?+ Width * Height);}
}public?class?Square?:?Rectangle
{public?override?double?Width?{//?get;set???//??因為是正方形,想當然重設了寬=高{base.Width=?value;base.Height=?value;}}public?override?double?Height{//??get;set??//??因為是正方形,想當然重設了寬=高{base.Width?=?value;base.Height?=?value;}}public?override?void?Area(){Console.WriteLine("面積是:"?+ Width * Width);}?
}public??class?Program
{public?static?void?Main(){Rectangle?s?=?new?Rectangle();s.Width?=?2;??????????s.Height?=?3;?????????s.Area();}
}output:
面積是:6

但是如果你[使用子類對象去替換父類對象]:

Rectangle?s2?=?new?Square();s2.Width?=?2;??????????s2.Height?=?3;?????????s2.Area();output:
面積是:9

Get到了嗎?我們不能想當然的認為子類對象就能無損替換父類對象, 根本原因是我們正方形雖然是(is a)矩形,但是我們的重寫行為破壞了父類的表達,這是一種繼承的誤用。

里氏替代原則就是約束你在繼承(is a)的時候注意到這個現象,并提醒你規避這個問題。

這個時候,不應該重寫父類的SetWight方法, 而應該擴展新的方法SetLength。

接口隔離?

將胖接口修改為多個小接口,調用接口的代碼應該比實現接口的代碼更依賴于接口。

why:如果一個類實現了胖接口的所有方法(部分方法在某次調用時并不需要),那么在該次調用時我們就會發現此時出現了(部分并不需要的方法),而并沒有機制告訴我們現在不應該使用這部分方法。

how:
避免胖接口,不要實現違反單一職責原則的接口。可以根據實際多職責劃分為多接口,某個類實現多接口后, 在調用時以特定接口指代對象,這樣這個對象只能體現特定接口的方法,以此體現接口隔離。

public?interface?IA{void?getA();}interface?IB{void?getB();}public?class?Test?:?IA,?IB{public?string?Field?{?get;?set;?}public?void?getA(){throw?new?NotImplementedException();}public?void?getB(){throw?new?NotImplementedException();}}class?Program{static?void?Main(string[]?args){Console.WriteLine("Hello?World!");IA?a?=?new?Test();a.getA();???????//??在這個調用處只能看到接口IA的方法,?接口隔離}}

依賴倒置原則

實現依賴于抽象, 抽象不依賴于細節。

Q:這個原則我其實一開始沒能理解什么叫“倒置”?

A: 但有了一點開發經驗后開始有點心得了。

痛點:面向過程的開發,上層調用下層,上層依賴于下層。當下層變動時上層也要跟著變動,導致模塊復用度降低,維護成本增高。

5d1745f7cbde8e00fa429ed55c6863c2.png

提煉痛點:含有高層策略的模塊,如AutoSystem模塊,依賴于它所控制的低層的負責具體細節的模塊。

思路:找到一種方法使AutoSystem模塊獨立于它所控制的具體細節,那么我們就可以自由地復用AutoSystem了;同時讓底層汽車廠也依賴抽象,受抽象驅動,這就形成一種“倒置”。

cd15cb8114597691f301d9cc5698ebcb.png

所以依賴倒置原則有兩個關鍵體現:

  1. ①? 高層次模塊不應該依賴于低層實現,而都應該依賴于抽象;

    這在上圖:AutoSystem和Car都依賴于抽象接口ICar
  2. ②? 抽象不應該依賴于具體實現,具體實現應該依賴于抽象。

    第2點與第1點不是重復的,這一點意味著細節實現是受抽象驅動,這也是“倒置”的由來,?這一點是通過接口叫ICar而不是IAutoSystem來體現。

面相對象五大設計原則SOLID,是指導思想,不貫徹這5大設計原則也能讓程序跑起來,但是可能就會出現閱讀性、維護性、正確性問題。

本人會不時修正理解、更正錯誤,請適時移步左下角永久更新地址;也請看客大膽斧正。

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

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

相關文章

python函數式編程-匿名函數

>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]) [1, 4, 9, 16, 25, 36, 49, 64, 81] 關鍵字lambda表示匿名函數,冒號前面的x表示函數參數。 匿名函數有個限制,就是只能有一個表達式,不用寫return,返回值就是該表…

bean初始化、注銷

關于在spring 容器初始化 bean 和銷毀前所做的操作定義方式有三種: 第一種:通過PostConstruct 和 PreDestroy 方法 實現初始化和銷毀bean之前進行的操作 第二種是:通過 在xml中定義init-method 和 destory-method方法 第三種是:…

谷歌F12調試公眾號時,讓鼠標顯示出來

yi 環境介紹: win10 , 谷歌瀏覽器yii 概述: 在項目中,需要調試公眾號,本地環境搭好之后,在谷歌瀏覽時,發現移動到公眾號區域,鼠標居然不見了,這讓我怎么操作?各種操作可謂是日了狗了,非常麻煩yiii 調試時鼠標不見的解決辦法: 網上各種說法眾說紛紜,這里,我給出本人認為最恰當簡…

利用bootstrap插件設置時間

$("#"id_rand" .shijian-input").each(function () { $(this).datetimepicker({ lang:"ch", //語言選擇中文 注:舊版本 新版方法:$.datetimepicker.setLocale(ch); format: "hh : ii", /…

C# 編寫的 64位操作系統 -MOOS

MOOSMOOS ( My Own Operating System )是一個使用.NET Native AOT技術編譯的C# 64位操作系統。項目地址:https://github.com/nifanfa/MOOS編譯關于編譯MOOS的信息,請閱讀 編譯維基頁面:https://github.com/nifanfa/MOOS/wiki/。編譯要求VMwar…

js獲取屏幕寬高和下拉加載更多

document.body.clientWidth > BODY對象寬度 document.body.clientHeight > BODY對象高度 document.documentElement.clientWidth > 可見區域寬度 document.documentElement.clientHeight > 可見區域高度 網頁可見區域寬: document.body.clientWid…

X5開發中buttongrounp對應contents組件切換時速度快點無效

官方提供的解決辦法是:http://docs.wex5.com/wex5-ui-question-list-2084/ 原文如下:【問題】buttongrounp中的button按鈕全是代碼動態生成,對應的contents中的content也是代碼動態生成。發現在快讀點擊button的時候,content就會死…

JAVA語言基礎-面向對象(IO:IO字符流、遞歸)

2019獨角獸企業重金招聘Python工程師標準>>> 21.01_IO流(字符流FileReader) 1.字符流是什么 字符流是可以直接讀寫字符的IO流字符流讀取字符, 就要先讀取到字節數據, 然后轉為字符. 如果要寫出字符, 需要把字符轉為字節再寫出.2.FileReader FileReader類的read()方法…

windows下, nginx 提示錯誤 No input file specified

一 環境介紹: win10, LNMP 二 錯誤描述: 訪問網站時,提示"No input file specified"錯誤. 排錯階段: 1. 查看nginx access日志 (access.log) 發現提示404 錯誤 2. 分析原因: 這時,在同目錄下創建一個txt文件,訪問就可以正常輸出了 這說明 現在nginx 訪問php 沒…

Ubuntu20.04+docker+jenkins+飛書實現自動化發布

一、從0-1一點一滴實現如何本地提交代碼到gitlab然后實現前后端自動發布1.更新apt包索引sudo apt-get update2.安裝必備的軟件包以允許apt通過https使用存儲庫sudo apt-get install ca-certificates curl gnupg lsb-release3.添加Docker官方版本的GPG密鑰sudo mkdir -p /etc/ap…

一個Demo讓你掌握Android所有控件

一個Demo讓你掌握Android所有控件 原文:一個Demo讓你掌握Android所有控件本文是轉載收藏,侵刪,出處:"安卓巴士" 下面給出實現各個組件的源代碼: 1.下拉框實現--Spinner [java] view plaincopyprint?package com.cellcom; import java.util.ArrayList;…

九妹帶你走向 架構師

邁向系統架構師編者按:系統架構師是許多程序員的夢想職業。今天的你也許已經掌握了各種開發工具,并且能夠使用各種平臺進行開發,但作為一個架構師的要求,也許還有很長的道路。邢波濤先生在LAMP架構上的造詣,讓我邀請他…

WPF 使用 DrawingContext 繪制溫度計

WPF 使用 DrawingContext 繪制溫度計控件名:Thermometer作者: WPFDevelopersOrg原文鏈接: https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40;Visual Studio 2022;項目使用 MIT 開源許可協議&#xff…

MAVEN簡介之——settings.xml

概述 Maven的settings.xml配置了Maven執行的方式,像pom.xml一樣,但是它是一個通用的配置,不能綁定到任何特殊的項目。它通常包括本地倉庫地址,遠程倉庫服務,認證信息等。 settings.xml存在于兩個位置: mave…

裝win10系統

一、使用U盤介質安裝win10系統(官方方式) 官方安裝工具下載地址:https://www.microsoft.com/zh-cn/software-download/windows10 1、進入官方安裝工具下載頁面,點擊立即下載工具,下載安裝工具。2、下載完成后&#xff…

C#構造函數、操作符重載以及自定義類型轉換

構造器 構造器(構造函數)是將類型的實例初始化的特殊方法。構造器可分為實例構造器和類型構造器,本節將詳細介紹有關內容。 實例構造器 顧名思義,實例構造器的作用就是對類型的實例進行初始化。如果類沒有顯示定義任何構造器&…

「Dotnet 工具箱」 自動生成并綁定 Https 證書

這里是 Dotnet 工具箱,定期分享 Dotnet 有趣,有用的工具,不要忘記關注。介紹LettuceEncrypt 是一個使用 C# 開發的免費的工具,它和證書頒發機構 (CA)集成,比如 Lets Encrypt,它使用了…

1115: 零起點學算法22——華氏攝氏溫度轉換

1115: 零起點學算法22——華氏攝氏溫度轉換 Time Limit: 1 Sec Memory Limit: 64 MB 64bit IO Format: %lldSubmitted: 3522 Accepted: 1456[Submit][Status][Web Board]Description 輸入一個華氏溫度,根據公式C(5/9)(F-32)計算對應的攝氏溫度。 Input 輸入一個…

Navicat Premium 12 的安裝破解

Navicat 這款軟件可以說 是數據庫可視化操作的神器, 有綠色的 (最原始版本, 好像現在已經不維護了) , 有金色的 (改良收費版 ) , 還有彩色的 (最新版) , 這里 , 推薦使用彩色版 (也就是截止目前最新的版本 12.0.27). 操作的話, 感覺相比于小綠和小金有很大改進 , 很棒 , 在此給…

Vuejs——組件——slot內容分發

2019獨角獸企業重金招聘Python工程師標準>>> ①概述: 簡單來說,假如父組件需要在子組件內放一些DOM,那么這些DOM是顯示、不顯示、在哪個地方顯示、如何顯示,就是slot分發負責的活。 ②默認情況下 父組件在子組件內套的…