面向對象設計必須遵循的幾條原則

咱們知道軟件開發的需求老是不完整的,錯誤的,容易讓人產生誤解的,並且需求一直在變化,它主要表如今如下幾個方面:用戶對需求的見解,可能在於開發人員討論以及看到軟件新的可能性後發生變化;隨着對問題的熟悉,開發人員對問題領域的見解也會變化;不是需求在變,而是人們對需求的理解再變化。編程

咱們應該採用何種方法去應對需求變化呢?首先,在方法論層面咱們應該採用敏捷開發;其次,在代碼層面,使用OOD(Object-Oriented Design,面向對象設計),它的根本原則:面向接口編程;多用組合,而不是繼承;發現變化,封裝變化。但如何讓設計知足這個原則呢?咱們的先輩們總結出了5條設計原則,俗稱SOLID原則,這就是本期咱們要介紹的詳細內容。bash

單一職責原則(SRP,The Single Responsibility Principle)

Robert C. Martin 大師對於單一職責原則有這樣一個定義:一個類應該僅有一個引發它變化的緣由,而這個引發變化的緣由就是職責。那麼職責是什麼東西呢?先來講說咱們人類的職責。做爲項目經理,個人職責是:項目計劃、需求管理、項目成本控制、項目時間控制等,我須要處理不少事情,同時,這些事緊密相關的。對應到面向對象設計領域,一個類的職責應該包含多個相關的功能。好比說用戶控制類中通常包含了新增用戶、刪除用戶、修改用戶等相關功能。微信

開閉原則(OCP,The Open close Principle)

開閉原則就是說對擴展開發,對修改封閉。看到這裏,咱們不由會問:新增功能還能夠不用修改代碼呀? 這是如何作到的呀?實際上開閉原則指的是提供者增長新的功能,而使用者不須要修改代碼,而且增長的新功能不能是一個全新的功能,而是原有功能的替代實現。爲了幫助你們理解,我舉一個具體的例子。目前購物車有添加商品、計算價格兩個功能,而商品有香蕉、蘋果兩種。Java代碼以下:測試

public interface Item{
  public String getName();
  public float getPrice();
}
public class Apple implements Item {
    public String getName() {
        return "Apple";
    }

    public float getPrice() {
        return 5.0f;
    }
}

class Orange implements Item{
    public String getName() {
        return "Orange";
    }

    public float getunitPrice() {
        return 6.0f;
    }
}

public class ShopCar {
    List<Item> items = new ArrayList<Item>();
    public void addItem(Item item) {
        items.add(item);
    }

    public float calculateTotalPrice() {
        float total = 0.0f;
        for (Item i : items) {
           total += i.getPrice();
        }
        return total;
    }
}

複製代碼

咱們注意到當新增一個香蕉類,ShopCar類不用修改,這是由於香蕉類是原有功能的替代實現,而不是一個全新的功能,若是購物車中新增商品價格變化這一全新功能,則須要修改ShopCar類。ui

Liskov替換原則(LSP,The Liskov Substitutuin Principle)

LSP替換原則指的是:子類型可以徹底替換父類。它最經典的例子就是長方形和正方形。咱們知道正方形是一種特殊的長方形,可是在面向對象設計領域,正方形並不能做爲長方形的子類。緣由在於設置正方形的長或寬時,同時設置了它的寬或長,那麼,正方形的面積等於最後一次設定的長或寬的平方,而不是長乘以寬。具體Java代碼以下:this

// 長方形
public class Rectangle {
  protected int width;
  protected int height;
  public void setWidth(int width){
    this.width = width;
  }
  public void setHeight(int height){
    this.height = height;
  }
  public int area(){
    return width*height;
  }
}
// 正方形
public class Squrare extends Rectangle{

  public void setWidth(int width){
    this.width = width;
    this.height = height;
  }
  public void setHeight(int height){
     this.width = width;
     this.height = height;
  }
}
// 測試類
public class Test{
  public static void main(String[] args){  
        Rectangle rectangle = new Rectangle();  
        rectangle.setWidth(4);  
        rectangle.setHeight(5);  
        // 正確
        assert( rectangle.getArea() == 20);  
          
        rectangle = new Square();  
        rectangle.setWidth(4);  
        rectangle.setHeight(5);  
        // 錯誤,此時正方形面積是25
        assert( rectangle.getArea() == 20);  
    }  
}

複製代碼

判斷一個子類是否知足LSP替換原則,咱們能夠像上面這個例子那樣,在測試類中用子類來替換父類。若是測試可以經過,則說明符合LSP原則,不然就說明不符合LSP原則。spa

接口隔離原則(ISP,The Interface  Segregation Interface)

雖然咱們要求軟件開發人員都要遵循SRP,可是不少狀況下類是沒有知足SRP原則的,這個時候就須要用到接口隔離原則。ISP原則指的是客戶端不該該被強迫去依賴它們並不須要的接口。也就是說,調用方調用的不須要是一個大而全的接口,而是一個小而精的接口。設計

依賴倒置原則(DIP,The Dependency Inversion Principle)

DIP包含兩層意思:1. 高層模塊不該該直接依賴低層模塊,二者都應該依賴抽象層;2. 抽象不能依賴細節,細節必須依賴抽象。這裏模塊是個廣義概念,能夠是系統、子系統、子模塊,甚至是類。而依賴包含多層意思:高層模塊調用底層模塊的方法,底層模塊繼承或實現抽象層。3d


image

歡迎關注微信公衆號:木可大大,全部文章都將同步在公衆號上。code

相關文章
相關標籤/搜索