亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談C#六大設(shè)計(jì)原則

 更新時(shí)間:2020年06月10日 16:32:57   作者:癡者工良  
這篇文章主要介紹了C#六大設(shè)計(jì)原則的相關(guān)內(nèi)容,文中代碼非常細(xì)致,供大家參考和學(xué)習(xí),感興趣的朋友可以了解下

筆者作為一個(gè)菜鳥(niǎo),會(huì)嘗試以簡(jiǎn)單的代碼和容易理解的語(yǔ)句去解釋這幾種原則的特性和應(yīng)用場(chǎng)景。

這六種原則分別為單一職責(zé)原則、接口隔離原則、里氏替換原則、迪米特法則、依賴(lài)倒置原則、開(kāi)閉原則。

單一職責(zé)原則

單一職責(zé)原則(SRP:Single responsibility principle),規(guī)定一個(gè)類(lèi)中應(yīng)該只有一個(gè)原因引起類(lèi)的變化。

單一職責(zé)原則的核心就是解耦和增強(qiáng)內(nèi)聚性。

問(wèn)題:

 // 假設(shè)此類(lèi)是數(shù)據(jù)庫(kù)上下文
 public class DatabaseContext { }

 public class Test
 {
  private readonly DatabaseContext _context;
  public Test(DatabaseContext context)
  {
   _context = context;
  }

  // 用戶(hù)登錄
  public void UserLogin() { }

  // 用戶(hù)注銷(xiāo)
  public void UserLogout() { }

  // 新增一個(gè)用戶(hù)
  public void AddUser() { }

  // 修改一個(gè)用戶(hù)的信息
  public void UpdateUser() { }

  // 刪除一個(gè)用戶(hù)
  public void DeleteUser() { }
 }

Test 負(fù)責(zé) 職責(zé) P1(用戶(hù)登錄和退出)和 P2(用戶(hù)賬號(hào)管理) 兩個(gè)職責(zé),當(dāng)由于職責(zé) P1 的需求發(fā)生變化而需要修改類(lèi)時(shí), 有可能會(huì)導(dǎo)致正常職責(zé) P2 的功能發(fā)生故障。

上面的代碼中,兩個(gè)職責(zé)被耦合起來(lái),擔(dān)任了多種功能。

一個(gè)類(lèi)中應(yīng)該只有一個(gè)原因引起類(lèi)的變化,也就要求一個(gè)類(lèi)只應(yīng)該負(fù)責(zé)一個(gè)功能,類(lèi)中地代碼是緊密聯(lián)系的。

上面的示例代碼非常簡(jiǎn)單,我們可以很自然地將一個(gè)個(gè)類(lèi)分為兩個(gè)部分。

 // 假設(shè)此類(lèi)是數(shù)據(jù)庫(kù)上下文
 public class DatabaseContext { }

 public class Test1
 {
  private readonly DatabaseContext _context;
  public Test1(DatabaseContext context)
  {
   _context = context;
  }

  // 用戶(hù)登錄
  public void UserLogin() { }

  // 用戶(hù)注銷(xiāo)
  public void UserLogout() { }

 }

 public class Test2
 {
  private readonly DatabaseContext _context;
  public Test2(DatabaseContext context)
  {
   _context = context;
  }
  // 新增一個(gè)用戶(hù)
  public void AddUser() { }

  // 修改一個(gè)用戶(hù)的信息
  public void UpdateUser() { }

  // 刪除一個(gè)用戶(hù)
  public void DeleteUser() { }
 }

因此,單一職責(zé)原則的解決方法,是將不同職責(zé)封裝到不同的類(lèi)或模塊中。

接口隔離原則

接口隔離原則(ISP:Interface Segregation Principle) 要求對(duì)接口進(jìn)行細(xì)分,類(lèi)的繼承建立在最小的粒度上,確保客戶(hù)端繼承的接口中,每一個(gè)方法都是它需要的。

筆者查閱了國(guó)外一些資料,大多將接口隔離原則定義為:

“Clients should not be forced to depend upon interfaces that they do not use.”

意思是不應(yīng)強(qiáng)迫客戶(hù)依賴(lài)于它不使用的方法。

對(duì)于此原則的解釋?zhuān)@篇文章講的非常透徹:

https://stackify.com/interface-segregation-principle/

這就要求我們拆分臃腫的接口成為更小的和更具體的接口,使得接口負(fù)責(zé)的功能更加單一。

目的:通過(guò)將軟件分為多個(gè)獨(dú)立的部分來(lái)減少所需更改的副作用和頻率。

筆者想到從兩方面論述:

其一,在描述多種動(dòng)物時(shí),我們可能會(huì)將不同種類(lèi)的動(dòng)物分類(lèi)。但是這還不夠,例如在鳥(niǎo)類(lèi)中,我們印象中鳥(niǎo)的特征是鳥(niǎo)會(huì)飛,但是企鵝不會(huì)飛~。

那么還要對(duì)物種的特征進(jìn)行細(xì)分,例如血液是什么顏色的、有沒(méi)有脊椎等。

其二,我們可以通過(guò)下面代碼表達(dá):

 // 與登錄有關(guān)
 public interface IUserLogin
 {
  // 登錄
  void Login();

  // 注銷(xiāo)
  void Logout();
 }

 // 與用戶(hù)賬號(hào)有關(guān)
 public interface IUserInfo
 {
  // 新增一個(gè)用戶(hù)
  void AddUser();

  // 修改一個(gè)用戶(hù)的信息
  void UpdateUser();

  // 刪除一個(gè)用戶(hù)
  void DeleteUser();
 }

上面的兩個(gè)接口,各種實(shí)現(xiàn)不同的功能,彼此沒(méi)有交叉,完美。

接下來(lái)我們看看兩個(gè)繼承了 IUserLogin 接口的代碼

 // 對(duì)用戶(hù)登錄注銷(xiāo)進(jìn)行管理,資源準(zhǔn)備和釋放
 public class Test1 : IUserLogin
 {
  public void Login(){}

  public void Logout(){}
 }

 public class Test2 : IUserLogin
 {
  public void Login()
  {
   // 獲取用戶(hù)未讀消息
  }

  public void Logout()
  {
  }
 }

對(duì)于 Test1 ,根據(jù)登錄和注銷(xiāo)兩個(gè)狀態(tài),進(jìn)行不同操作。

但是,對(duì)于 Test2,它只需要登錄這個(gè)狀態(tài),其它情況不關(guān)它事。那么 Logout() 對(duì)他來(lái)說(shuō),完全沒(méi)有用,這就是接口污染。

上面的代碼就違法了接口隔離原則。

但是,接口隔離原則有個(gè)缺點(diǎn),就是容易過(guò)多地將細(xì)分接口。一個(gè)項(xiàng)目中,出現(xiàn)成千上萬(wàn)個(gè)接口,將是維護(hù)地災(zāi)難。

因此接口隔離原則要靈活使用,就 Test2 來(lái)說(shuō),多繼承一個(gè)方法無(wú)傷大礙,不用就是了。ASP.NET Core 中就存在很多這樣的實(shí)現(xiàn)。

  public void Function()
  {
   throw new NotImplementedException();
  }

《設(shè)計(jì)模式之禪》第四章中,作者對(duì)接口隔離原則總結(jié)了四個(gè)要求:

1  接口盡量小:不出現(xiàn)臃腫(Fat)的接口。

2  接口要高內(nèi)聚:提高接口、類(lèi)、模塊的處理能力。

3  定制服務(wù):小粒度的接口可以組成大接口,靈活定制新的功能。

4  接口的設(shè)計(jì)有限度:難以有固定的標(biāo)準(zhǔn)去衡量接口的粒度是否合理。

另外還有關(guān)于單一職責(zé)原則和接口隔離原則的關(guān)系和對(duì)比。

單一職責(zé)原則是從服務(wù)提供者的角度去看,提供一個(gè)高內(nèi)聚的、單一職責(zé)的功能;

接口隔離原則是從使用者角度去看,也是實(shí)現(xiàn)高內(nèi)聚和低耦合。

接口隔離原則的粒度可能更小,通過(guò)多個(gè)接口靈活組成一個(gè)符合單一職責(zé)原則的類(lèi)。

我們也看到了,單一職責(zé)原則更多是圍繞類(lèi)來(lái)討論;接口隔離原則是對(duì)接口來(lái)討論,即對(duì)抽象進(jìn)行討論。

開(kāi)閉原則

開(kāi)閉原則(Open/Closed Principle)規(guī)定 :

“軟件中的對(duì)象(類(lèi),模塊,函數(shù)等等)應(yīng)該對(duì)于擴(kuò)展是開(kāi)放的,但是對(duì)于修改是封閉的”

--《Object-Oriented Software Construction》作者 Bertrand Meyer
開(kāi)閉原則意味著一個(gè)實(shí)體是允許在不改變它的源代碼的前提下變更它的行為。類(lèi)的改動(dòng)是通過(guò)增加代碼實(shí)現(xiàn),而不是修改源代碼。

開(kāi)閉原則 有 梅耶開(kāi)閉原則、多態(tài)開(kāi)閉原則。

梅耶開(kāi)閉原則

​       代碼一旦完成,一個(gè)類(lèi)的實(shí)現(xiàn)只應(yīng)該因錯(cuò)誤而修改,新的或者改變的特性應(yīng)該通過(guò)新建不同的類(lèi)實(shí)現(xiàn)。

​       特點(diǎn):繼承,子類(lèi)繼承父類(lèi),擁有其所有的方法,并且拓展。

多態(tài)開(kāi)閉原則

​       此原則使用接口而不是父類(lèi)來(lái)允許不同的實(shí)現(xiàn),您可以在不更改它們的代碼的情況下輕松替換它們。

現(xiàn)在大多數(shù)情況下,開(kāi)閉原則指的是多態(tài)開(kāi)閉原則。

多態(tài)開(kāi)閉原則筆者在查閱資料是,發(fā)現(xiàn)這個(gè)接口指的不是 Interface ,指的是抽象方法、虛方法。

問(wèn):面向?qū)ο蟮娜筇匦允鞘裁矗看穑悍庋b、繼承、多態(tài)。

對(duì),多態(tài)開(kāi)閉原則就是指這個(gè)多態(tài)。不過(guò),原則要求不應(yīng)對(duì)方法進(jìn)行重載(重寫(xiě))、隱藏。

這是一個(gè)示例:

 // 實(shí)現(xiàn)登錄注銷(xiāo)
 public class UserLogin
 {
  public void Login() { }
  public void Logout() { }
  public virtual void A() {/* 做了一些事*/}
  public virtual void B() {/* 也做了一些事*/ }
 }
 public class UserLogin1 : UserLogin
 {
  public void Login(string userName) { }  // 應(yīng)不應(yīng)該對(duì)父類(lèi)的方法進(jìn)行重載?
  public override void A() { }    // √
  public override void B() { }    // √
  public new void Logout() { }    // 也許行?
 }

多態(tài)開(kāi)閉原則的好處是,引入了抽象,使得兩個(gè)類(lèi)松耦合,而且可以使得在不修改代碼的前提下,使用子類(lèi)替換父類(lèi)(里氏替換原則)。

有時(shí),會(huì)看到這樣的題目:接口和抽象類(lèi)的區(qū)別?

筆者隱約記得有過(guò)一條這樣的解釋?zhuān)航涌谑菫榱藢?shí)現(xiàn)共同的標(biāo)準(zhǔn);抽象是為了代碼的復(fù)用。

當(dāng)然,接口和抽象,都可以實(shí)現(xiàn)里氏替換。

通過(guò)開(kāi)閉原則,我們可以了解到多態(tài),也了解接口和抽象的應(yīng)用場(chǎng)景。

還有一個(gè)問(wèn)題是,開(kāi)閉原則要求是要修改或添加功能時(shí),通過(guò)子類(lèi)來(lái)實(shí)現(xiàn),而不是修改原有代碼。那么是否可以和應(yīng)該對(duì)父類(lèi)的代碼進(jìn)行重載和隱藏?

而開(kāi)閉原則的核心是構(gòu)造抽象,從而通過(guò)子類(lèi)派生來(lái)實(shí)現(xiàn)拓展。貌似沒(méi)有說(shuō)到這方面。

筆者覺(jué)得不太應(yīng)該。。。

先結(jié)合下面的里氏替換原則,我們?cè)儆懻撨@個(gè)問(wèn)題?

里氏替換原則

里氏替換原則(LSP:Liskov Substitution Principle)要求:凡是父類(lèi)出現(xiàn)的地方,子類(lèi)都可以出現(xiàn)。

這就要求了子類(lèi)必須與父類(lèi)具有相同的行為。只有當(dāng)子類(lèi)能夠替換任何父類(lèi)的實(shí)例時(shí),才會(huì)符合里氏替換原則。

里氏替換原則的約束:

1  子類(lèi)必須實(shí)現(xiàn)父類(lèi)的抽象方法,但不能重寫(xiě)父類(lèi)中已實(shí)現(xiàn)的方法。

2  子類(lèi)中可以增加方法拓展功能。

3  當(dāng)子類(lèi)覆蓋或?qū)崿F(xiàn)(虛擬方法/抽象方法)父類(lèi)的方法時(shí),方法的輸入?yún)?shù)限制更加寬松并且返回值要比父類(lèi)方法更加嚴(yán)格。

所以,我們看到開(kāi)閉原則中的示例,子類(lèi)應(yīng)不應(yīng)該重載父類(lèi)的方法?應(yīng)不應(yīng)該使用 new 關(guān)鍵字隱藏父類(lèi)的方法?為了確保子類(lèi)繼承后,還具有跟父類(lèi)一致的特性,不建議這樣做呢,親。

實(shí)現(xiàn)了開(kāi)閉原則,自然可以使用里氏替換原則。

依賴(lài)倒置原則

依賴(lài)倒置原則(Dependence Inversion Principle)要求程序要依賴(lài)于抽象接口,不要依賴(lài)于具體實(shí)現(xiàn)。

我們可以從代碼中,慢慢演進(jìn)和推導(dǎo)理論。

 // 實(shí)現(xiàn)登錄注銷(xiāo)
 public class UserLogin
 {
  public void Login(){}
  public void Logout(){}
 }

 public class Test1 : UserLogin { }

 public class Test2
 {
  private readonly UserLogin userLogin = new UserLogin();
 }

 public class Test3
 {
  private readonly UserLogin _userLogin;
  public Test3(UserLogin userLogin)
  {
   _userLogin = userLogin;
  }
 }

上面代碼中,Test1、Test2、Test3 都依賴(lài) UserLogin 。先不說(shuō)上面代碼有什么毛病,根據(jù)依賴(lài)倒置原則,應(yīng)該是這樣編寫(xiě)代碼的

 // 與登錄有關(guān)
 public interface IUserLogin
 {
  void Login();  // 登錄
  void Logout();  // 注銷(xiāo)
 }

 // 實(shí)現(xiàn)登錄注銷(xiāo)
 public class UserLogin1 : IUserLogin
 {
  public void Login(){}
  public void Logout(){}
 }
 
 // 實(shí)現(xiàn)登錄注銷(xiāo)
 public class UserLogin2 : IUserLogin
 {
  public void Login(){}
  public void Logout(){}
 }

 public class Test4
 {
  private readonly IUserLogin _userLogin;
  public Test4(IUserLogin userLogin)
  {
   _userLogin = userLogin;
  }
 }

依賴(lài)倒置原則,在于引入一種抽象,這種抽象將高級(jí)模塊和底層模塊彼此分離。高層模塊和底層模塊松耦合,底層模塊的變動(dòng)不需要高層模塊也要變動(dòng)。

依賴(lài)導(dǎo)致原則有兩個(gè)思想:

1  高層模塊不應(yīng)該依賴(lài)于底層模塊,兩者都應(yīng)該依賴(lài)于抽象。

2  抽象不應(yīng)該依賴(lài)細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴(lài)于抽象。

因?yàn)橐蕾?lài)于抽象,底層模塊可以任意替換一個(gè)實(shí)現(xiàn)了抽象的模塊。

里氏替換原則是要求子類(lèi)父類(lèi)行為一致,子類(lèi)可以替換父類(lèi)。

依賴(lài)倒置原則,每個(gè)方法的行為是可以完全不一樣的。

迪米特法則

迪米特法則(Law of Demeter)要求兩個(gè)類(lèi)之間盡可能保持最小的聯(lián)系。

例如 對(duì)象A 不應(yīng)該直接調(diào)用 對(duì)象B,而是應(yīng)該通過(guò) 中間對(duì)象C 來(lái)保持通訊。

請(qǐng)參考 https://en.wikipedia.org/wiki/Law_of_Demeter

優(yōu)勢(shì):松耦合,較少了依賴(lài)。

缺點(diǎn):要編寫(xiě)許多包裝代碼,增加復(fù)雜讀,模塊之間的通訊效率變低。

筆者找了很多資料,發(fā)現(xiàn)都是 java 的。。。

一般來(lái)說(shuō),較少會(huì)提到迪米特原則,代碼符合依賴(lài)倒置原則和里氏替換原則等,也就算是符合迪米特法則了。

以上就是淺談C#六大設(shè)計(jì)原則的詳細(xì)內(nèi)容,更多關(guān)于C#六大設(shè)計(jì)原則的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#類(lèi)型轉(zhuǎn)換之自定義隱式轉(zhuǎn)換和顯式轉(zhuǎn)換

    C#類(lèi)型轉(zhuǎn)換之自定義隱式轉(zhuǎn)換和顯式轉(zhuǎn)換

    本文主要為大家介紹了一個(gè)新的類(lèi)型轉(zhuǎn)換方法:通過(guò)自定義隱式轉(zhuǎn)換,把不一樣的數(shù)據(jù)類(lèi)型反序列化為一樣的數(shù)據(jù)類(lèi)型,需要的同學(xué)可以參考一下
    2022-03-03
  • C#創(chuàng)建Excel多級(jí)分組的方法

    C#創(chuàng)建Excel多級(jí)分組的方法

    這篇文章主要為大家詳細(xì)介紹了C#創(chuàng)建Excel多級(jí)分組的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • C#執(zhí)行js動(dòng)態(tài)編譯的方法

    C#執(zhí)行js動(dòng)態(tài)編譯的方法

    這篇文章主要介紹了C#執(zhí)行js動(dòng)態(tài)編譯的方法,是涉及動(dòng)態(tài)編譯腳本非常實(shí)用的技巧,需要的朋友可以參考下
    2015-01-01
  • 詳解C#中Helper類(lèi)的使用

    詳解C#中Helper類(lèi)的使用

    項(xiàng)目中用戶(hù)頻繁訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)會(huì)導(dǎo)致程序的卡頓,甚至堵塞。使用緩存可以有效的降低用戶(hù)訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的頻次,有效的減少并發(fā)的壓力。而helper類(lèi)對(duì)緩存有了封裝,本文展示了封裝的示例代碼,需要的可以參考一下
    2022-04-04
  • c#使用Unity粒子實(shí)現(xiàn)炮塔發(fā)射系統(tǒng)

    c#使用Unity粒子實(shí)現(xiàn)炮塔發(fā)射系統(tǒng)

    Unity自帶粒子發(fā)射器、動(dòng)畫(huà)器、渲染器各兩種,利用Unity的粒子系統(tǒng)制作一個(gè)炮塔發(fā)射系統(tǒng),了解粒子系統(tǒng),必須先了解每一個(gè)屬性都代表了什么,之后才能根據(jù)這些原理來(lái)調(diào)整出自己滿(mǎn)意的效果
    2022-04-04
  • 深入理解C#指針之美

    深入理解C#指針之美

    在C#中,有時(shí)候希望通過(guò)指針來(lái)操作內(nèi)存,這樣可以提高效率。我們可以用unsafe關(guān)鍵字修飾含有指針操作的程序段,感興趣的小伙伴可以參考一下,希望可以幫到你
    2021-07-07
  • C# Unicode編碼解碼的實(shí)現(xiàn)

    C# Unicode編碼解碼的實(shí)現(xiàn)

    本文主要介紹了C# Unicode編碼解碼的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C#實(shí)現(xiàn)Excel合并單元格數(shù)據(jù)導(dǎo)入數(shù)據(jù)集詳解

    C#實(shí)現(xiàn)Excel合并單元格數(shù)據(jù)導(dǎo)入數(shù)據(jù)集詳解

    這篇文章主要為大家詳細(xì)介紹了C#如何實(shí)現(xiàn)Excel合并單元格數(shù)據(jù)導(dǎo)入數(shù)據(jù)集,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • C#使用FileStream復(fù)制一個(gè)任意文件

    C#使用FileStream復(fù)制一個(gè)任意文件

    這篇文章主要為大家詳細(xì)介紹了C#使用FileStream復(fù)制一個(gè)任意文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • C# 讀取指定路徑配置文件的方法

    C# 讀取指定路徑配置文件的方法

    為了實(shí)現(xiàn)多個(gè)C#程序共用一個(gè)config文件,需要程序讀取指定路徑的config文件。代碼如下:
    2013-03-03

最新評(píng)論