使用設計模式的根本原因是適應變化,提高代碼複用率,使軟件更具有可維護性和可擴展性。並且,在進行設計的時候,也需要遵循以下幾個原則:單一職責原則、開放封閉原則、里氏代替原則、依賴倒置原則、接口隔離原則、合成複用原則和迪米特法則。下面就分別介紹了每種設計原則。
2.1 單一職責原則
就一個類而言,應該只有一個引起它變化的原因。如果一個類承擔的職責過多,就等於把這些職責耦合在一起,一個職責的變化可能會影響到其他的職責,另外,把多個職責耦合在一起,也會影響複用性。
2.2 開閉原則(Open-Closed Principle)
開閉原則即OCP(Open-Closed Principle縮寫)原則,該原則強調的是:一個軟件實體(指的類、函數、模塊等)應該對擴展開放,對修改關閉。即每次發生變化時,要通過添加新的代碼來增強現有類型的行爲,而不是修改原有的代碼。
符合開閉原則的最好方式是提供一個固有的接口,然後讓所有可能發生變化的類實現該接口,讓固定的接口與相關對象進行交互。
2.3 里氏代替原則(Liskov Substitution Principle)
Liskov Substitution Principle,LSP(里氏代替原則)指的是子類必須替換掉它們的父類型。也就是說,在軟件開發過程中,子類替換父類後,程序的行爲是一樣的。只有當子類替換掉父類後,此時軟件的功能不受影響時,父類才能真正地被複用,而子類也可以在父類的基礎上添加新的行爲。爲了就來看看違反了LSP原則的例子,具體代碼如下所示:
public class Rectangle { public virtual long Width { get; set; } public virtual long Height { get; set; } } // 正方形 public class Square : Rectangle { public override long Height { get { return base.Height; } set { base.Height = value; base.Width = value; } } public override long Width { get { return base.Width; } set { base.Width = value; base.Height = value; } } } class Test { public void Resize(Rectangle r) { while (r.Height >= r.Width) { r.Width += 1; } } var r = new Square() { Width = 10, Height = 10 }; new Test().Resize(r); }
上面的設計,正如上面註釋的一樣,在執行SmartTest的resize方法時,如果傳入的是長方形對象,當高度大於寬度時,會自動增加寬度直到超出高度。但是如果傳入的是正方形對象,則會陷入死循環。此時根本原因是,矩形不能作爲正方形的父類,既然出現了問題,可以進行重構,使它們倆都繼承於四邊形類。重構後的代碼如下所示:
// 四邊形 public abstract class Quadrangle { public virtual long Width { get; set; } public virtual long Height { get; set; } } // 矩形 public class Rectangle : Quadrangle { public override long Height { get; set; } public override long Width { get; set; } } // 正方形 public class Square : Quadrangle { public long _side; public Square(long side) { _side = side; } } class Test { public void Resize(Quadrangle r) { while (r.Height >= r.Width) { r.Width += 1; } } static void Main(string[] args) { var s = new Square(10); new Test().Resize(s); } }
2.4 依賴倒置原則
依賴倒置(Dependence Inversion Principle, DIP)原則指的是抽象不應該依賴於細節,細節應該依賴於抽象,也就是提出的 “面向接口編程,而不是面向實現編程”。這樣可以降低客戶與具體實現的耦合。
2.5 接口隔離原則
接口隔離原則(Interface Segregation Principle, ISP)指的是使用多個專門的接口比使用單一的總接口要好。也就是說不要讓一個單一的接口承擔過多的職責,而應把每個職責分離到多個專門的接口中,進行接口分離。過於臃腫的接口是對接口的一種污染。
2.6 合成複用原則
合成複用原則(Composite Reuse Principle, CRP)就是在一個新的對象裏面使用一些已有的對象,使之成爲新對象的一部分。新對象通過向這些對象的委派達到複用已用功能的目的。簡單地說,就是要儘量使用合成/聚合,儘量不要使用繼承。
要使用好合成複用原則,首先需要區分"Has—A"和“Is—A”的關係。
“Is—A”是指一個類是另一個類的“一種”,是屬於的關係,而“Has—A”則不同,它表示某一個角色具有某一項責任。導致錯誤的使用繼承而不是聚合的常見的原因是錯誤地把“Has—A”當成“Is—A”.例如:
實際上,僱員、經歷、學生描述的是一種角色,比如一個人是“經理”必然是“僱員”。在上面的設計中,一個人無法同時擁有多個角色,是“僱員”就不能再是“學生”了,這顯然不合理,因爲現在很多在職研究生,即使僱員也是學生。
上面的設計的錯誤源於把“角色”的等級結構與“人”的等級結構混淆起來了,誤把“Has—A”當作"Is—A"。具體的解決方法就是抽象出一個角色類:
2.7 迪米特法則
迪米特法則(Law of Demeter,LoD)又叫最少知識原則(Least Knowledge Principle,LKP),指的是一個對象應當對其他對象有儘可能少的瞭解。也就是說,一個模塊或對象應儘量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立,這樣當一個模塊修改時,影響的模塊就會越少,擴展起來更加容易。
關於迪米特法則其他的一些表述有:只與你直接的朋友們通信;不要跟“陌生人”說話。
外觀模式(Facade Pattern)和中介者模式(Mediator Pattern)就使用了迪米特法則。
From https://www.cnblogs.com/zhili/p/DesignPatternSummery.html