重溫-設計原則

  使用設計模式的根本原因是適應變化,提高代碼複用率,使軟件更具有可維護性和可擴展性。並且,在進行設計的時候,也需要遵循以下幾個原則:單一職責原則、開放封閉原則、里氏代替原則、依賴倒置原則、接口隔離原則、合成複用原則和迪米特法則。下面就分別介紹了每種設計原則。

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 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章