設計模式學習筆記(二) 設計基本原則之【單一職責原則】
單一職責原則(SRP: Single Responsibility Principle)
名詞解釋:
1) 職責:是指類變化的原因。
2) 職責擴散:就是因為某種原因,職責P被分化為粒度更細的職責P1和P2。
3) 可變類:是指創建該類的實例後,可以對其屬性進行修改。
4)不可變類:是指創建該類的實例後,不可對其屬性進行修改。不可變類是線程安全的。
1、應用場景
一個類T負責兩個不同的職責:職責P1、職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能會導致原來運行的職責P2功能發生故障。
2、解決方案
分別建立兩個類T1、T2,使T1完成職責P1功能,T2完成職責P2功能。這樣,當修改類T1時,不會使職責P2發生故障風險;同理,當修改T2時,也不會使職責P1發生故障風險。
3、優點
-
可以降低類的復雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多。
-
提高類的可讀性,提高系統的可維護性。
-
變更引起的風險降低,實際應用中,變更是必然的,如果單一職責原則遵守的好,當修改一個功能時,可以顯著降低對其他功能的影響。
-
提供重用基礎:代碼塊獨立,功能單一,可以容易地重用。
-
提供可擴展性 :依賴別的單元提供的接口,便於擴展。
4、缺點
如果嚴格的遵循單一職責原則,即所有的類均只負責一項職責,開發者面對的將是巨量的類(類的爆炸),如果沒有一個清晰的類管理方法,勢必降低系統的可讀性和可維護性。
我們不可能針對每個類都設計原子級的職責。那麽就會牽涉到職責的組合和劃分,我們很難建立一個標準來界定如何對職責進行合理的劃分。職責的大小怎麽定義是個難題,什麽樣的職責放在一起是好的內聚也不好定義。
實際項目應用中很少能夠實現單一職責原則,必須考慮可變因素與不可變因素的影響和開發效率的問題。
5、實踐及示例
一般來說,接口的設計需嚴格遵守單一職責原則。如下圖說所示,我們定義一個文件操作的接口,實現文件的基本操作
代碼如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace LoadBalan 6 { 7 public interface IFileOperator 8 { 9 void Open(stringView CodefileName); 10 void Write(string fileName,byte[] fileData); 11 byte[] Read(); 12 void Save(string fileName); 13 void Close(string fileName); 14 } 15 16 class DisplayFile : IFileOperator 17 { 18 public void Open(string fileName) 19 { 20 21 } 22 23 public void Write(string fileName, byte[] fileData) 24 { 25 } 26 public byte[] Read() { 27 28 return null ; 29 } 30 public void Save(string fileName) 31 { 32 33 } 34 public void Close(string fileName) 35 { 36 37 } 38 } 39 class SaveFile : IFileOperator 40 { 41 public void Open(string fileName) 42 { 43 44 } 45 46 public void Write(string fileName, byte[] fileData) 47 { 48 } 49 public byte[] Read() 50 { 51 52 return null; 53 } 54 public void Save(string fileName) 55 { 56 57 } 58 public void Close(string fileName) 59 { 60 61 } 62 } 63 }
我們可以看到,IFileOperator接口包含了一系列的操作,而我們的DisplayFile類和SaveFile類都只是用到其中一部分操作,但都要實現該接口中所有的操作,造成大量的代碼冗余,也影響程序的可讀性。根據單一職責原則,我們做如下改進:
代碼如下(設計不一定合理,只是為了說明單一職責原則):
using System; using System.Collections.Generic; using System.Text; namespace LoadBalan { class Lesson_SRP02 { public interface IFileOperator { void Open(string fileName); void Close(string fileName); } public interface IFileRead { byte[] Read(); } public interface IFileSave { void Write(string fileName, byte[] fileData); void Save(string fileName); } class DisplayFile : IFileOperator,IFileRead { public void Open(string fileName) { } public byte[] Read() { return null; } public void Close(string fileName) { } } class SaveFile : IFileOperator { public void Open(string fileName) { } public void Write(string fileName, byte[] fileData) { } public void Save(string fileName) { } public void Close(string fileName) { } } } }View Code
這樣,DisplayFile類與SaveFile類裏就沒有冗余代碼,各自只實現自己所需的功能。
設計模式學習筆記(二) 設計基本原則之【單一職責原則】