設計目標
設計可維護性高,可復用性強的軟體,可維護性指的是軟體能夠被理解、修改、適用及擴展的難易程度,而可復用性指的是軟體能夠被重復使用的難易程度
設計原則分類

單一職責原則
定義
Single Responsibility Principle(SPR):一個類最好只負責一項事務,只有一個引起它改變的原因,單一職責原則是實作高內聚、低耦合的方式,其關鍵在于依據需求控制類的粒度大小,
案例
設計一個滿足用戶需求的智能手表,設計廠商設計了如下的智能手表介面
public interface IWatch { public string Cpu { get; set; } /// <summary> /// 記憶體 /// </summary> public string Ram { get; set; } /// <summary> /// 顯示屏尺寸 /// </summary> public int Size { get; set; } /// <summary> /// 計步 /// </summary> /// <returns></returns> int StepCount(); /// <summary> /// 心率 /// </summary> /// <returns></returns> int HeartRate(); /// <summary> /// 獲取時間 /// </summary> /// <returns></returns> TimeSpan GetTime(); }View Code
生產廠商完成了某款手表的設計
public class HuaWeiWatch : IWatch { public string Cpu { get; set; } public string Ram { get; set; } public int Size { get; set; } public int StepCount() { throw new System.NotImplementedException(); } public int HeartRate() { throw new System.NotImplementedException(); } public TimeSpan GetTime() { throw new NotImplementedException(); } }View Code
以手表為最小粒度去設計在可以保證功能與硬體設施不改變下也是可行的,但是一般情況智能手表的功能各不相同,硬體也略有差距,所以以手表本身為單一職責的目標進行設計介面不能完全滿足需求的變更,所以我們將手表的功能與需求分別定義介面規范
public interface IWatchFunction { /// <summary> /// 計步 /// </summary> /// <returns></returns> int StepCount(); /// <summary> /// 心率 /// </summary> /// <returns></returns> int HeartRate(); /// <summary> /// 獲取時間 /// </summary> /// <returns></returns> TimeSpan GetTime(); } public class WatchFunction : IWatchFunction { public int StepCount() { throw new NotImplementedException(); } public int HeartRate() { throw new NotImplementedException(); } public TimeSpan GetTime() { throw new NotImplementedException(); } }WatchFunction
public interface IWatchHardwareFacility { public string Cpu { get; set; } /// <summary> /// 記憶體 /// </summary> public string Ram { get; set; } /// <summary> /// 顯示屏尺寸 /// </summary> public int Size { get; set; } } public class WatchHardwareFacility : IWatchHardwareFacility { public string Cpu { get; set; } public string Ram { get; set; } public int Size { get; set; } }WatchHardwareFacility
手表實作類如下
public class HuaWeiWatch { public IWatchHardwareFacility WatchHardwareFacility { get; set; } public IWatchFunction WatchFunction { get; set; } public HuaWeiWatch(IWatchHardwareFacility watchHardwareFacility, IWatchFunction watchFunction) { WatchHardwareFacility = watchHardwareFacility; WatchFunction = watchFunction; } }View Code
現在手表實作類如果增加新功能只需要修改IWatchFunction和其實作,修改IWatchHardwareFacility和它的實作,貌似可以解決所有問題了,但是我們的同款智能手表可是會有基礎款與pro的區別的,pro會在基礎款的基礎上多一些擴展功能,依據這個需求又可以將功能分為基本功能與擴展功能,將硬體設施分為基礎硬體與擴展硬體,所以有了下面的實作
public interface IWatchBaseFunc { /// <summary> /// 計步 /// </summary> /// <returns></returns> int StepCount(); /// <summary> /// 心率 /// </summary> /// <returns></returns> int HeartRate(); /// <summary> /// 獲取時間 /// </summary> /// <returns></returns> TimeSpan GetTime(); } public class WatchBaseFunc : IWatchBaseFunc { public int StepCount() { throw new NotImplementedException(); } public int HeartRate() { throw new NotImplementedException(); } public TimeSpan GetTime() { throw new NotImplementedException(); } }WatchBaseFunc
public interface IWatchExtensionFunc { /// <summary> /// 移動支付 /// </summary> void MobilePayment(); } public class WatchExtensionFunc : IWatchExtensionFunc { public void MobilePayment() { throw new System.NotImplementedException(); } }WatchExtensionFunc
public interface IWatchBaseHardware { public string Cpu { get; set; } /// <summary> /// 記憶體 /// </summary> public string Ram { get; set; } /// <summary> /// 顯示屏尺寸 /// </summary> public int Size { get; set; } } public class WatchBaseHardware : IWatchBaseHardware { public string Cpu { get; set; } public string Ram { get; set; } public int Size { get; set; } }WatchBaseHardware
public interface IWatchExtensionHardware { /// <summary> /// 氣壓傳感器 /// </summary> public string Baroceptor { get; set; } } public class WatchExtensionHardware : IWatchExtensionHardware { public string Baroceptor { get; set; } }WatchExtensionHardware
上面實作了手表基礎款與pro款,如果還有其他更加細致的需求,粒度還可以再減小,所以單一職責的粒度控制最終由需求決定
依賴倒置原則
定義
Dependency Inversion Principle(DIP):高層模塊不應該依賴低層模塊,它們都應該依賴抽象,抽象不應該依賴于細節,細節應該依賴于抽象
案例
某用戶資料系統有Excel資料與Txt文本資料需要轉換存盤到資料庫中
namespace DependencyInversionPrinciple { public class Customer { } }Customer
namespace DependencyInversionPrinciple { public class DatabaseOperation { public static void AddCustomers(IConvertor convertor) { var customers = convertor.DataToCustomers(); Add(customers); } private static void Add(IEnumerable<Customer> customers) { Console.WriteLine("向資料庫中添加用戶資料"); } } }DatabaseOperation
namespace DependencyInversionPrinciple { public interface IConvertor { IEnumerable<Customer> DataToCustomers(); } }IConvertor
namespace DependencyInversionPrinciple { public class ExcelDataConvertor : IConvertor { public IEnumerable<Customer> DataToCustomers() { Console.WriteLine("將excel轉換成Customers集合"); return new List<Customer>(); } } }ExcelDataConvertor
namespace DependencyInversionPrinciple { public class TxtDataConvertor : IConvertor { public IEnumerable<Customer> DataToCustomers() { Console.WriteLine("將txt轉換成Customers集合"); return new List<Customer>(); } } }TxtDataConvertor
現在如果我們想要增加一個xml資料只需要添加一個XmlDataConvertor類實作IConvertor介面即可,這樣我們的上層資料庫操作類就只依賴于IConvertor的抽象物件
namespace DependencyInversionPrinciple { class Program { static void Main(string[] args) { IConvertor convertor = new ExcelDataConvertor(); DatabaseOperation.AddCustomers(convertor); Console.ReadKey(); } } }Main
當然我們也可以使用Unity等依賴注入容器在組態檔中決定使用哪種資料轉換類
開閉原則
定義
Open-Close Principle(OCP):軟體物體應該對擴展開放,對修改關閉
案例
在上述依賴倒置原則的例子中,如果我們需要增加新的xml用戶資料進行資料庫操作
namespace DependencyInversionPrinciple { public class XmlDataConvertor : IConvertor { public IEnumerable<Customer> DataToCustomers() { Console.WriteLine("將xml轉換成Customers集合"); return new List<Customer>(); } } }XmlDataConvertor
namespace DependencyInversionPrinciple { class Program { static void Main(string[] args) { IConvertor convertor = new XmlDataConvertor(); DatabaseOperation.AddCustomers(convertor); Console.ReadKey(); } } }Main
在需求變更后,我們只需要擴展一個新的類,其他方法不需要改動下即可完成功能
里氏代換原則
Liskov Substitution Principle(LSP):所有參考基類的地方都應該可以使用子類物件
結合依賴倒置原則,如果細節是依賴于抽象的話,那么子類實作都是基于介面的細節定義,在這種情況下如果沒有擴展功能子類是可以在任何時候被其他子類替換掉的,
介面隔離原則
定義
Interface Segregation Principle(ISP):客戶端不應該依賴于那些不需要的介面
結合單一職責原則我們可以理解為按照需求我們應該對介面功能過于臃腫的介面進行功能分類,比方說有一個IOrder介面,但是應為業務增長出現生產與銷售兩個部門,那么IOrder介面理應變成IProductOrder和ISaleOrder
合成復用原則
定義
Composite Reuse Principle(CRP):優先使用物件組合而不是直接繼承達到復用目的
使用類間關聯關系,即一個類中包含另一個物件,如果類內包含的該物件需要改變,可以對該物件做新的子類實作,子類實作符合里氏代換原則,這樣系統仍然符合開閉原則,
迪米特法則
定義
Law of Demeter(LoD):軟體單元之間應該減少不必要的聯系,類與類之間應該盡量減少耦合
在一個群聊系統中即存在一對一聊天,一對多聊天,也存在多對一的復雜關系,直接讓每個Person物件直接和其他相關聯加大了系統的耦合度,此時我們可以使用一個中間通訊員類進行訊息一對一,一對多,多對一的轉發從而降低系統耦合度,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/4860.html
標籤:C#
上一篇:C#設計模式
下一篇:設計模式中的那些工廠
