java 七大設計原則之迪米特原則,開閉原則,合成複用原則(文字代碼相結合理解)

java 七大設計原則之迪米特原則,開閉原則,合成複用原則 ---文字代碼相結合理解

七大設計原則有哪些?

  • 單一職責原則
  • 接口隔離原則
  • 依賴倒轉(倒置)原則
  • 里氏替換原則
  • 開閉原則
  • 迪米特法則
  • 合成複用原則

一般你們理解的是前六個,並無合成複用原則java

爲何要使用七大設計原則?

  • 代碼重用性(相同的代碼不用屢次編寫);
  • 可讀性(編程的規範性,便於其餘程序員的閱讀和理解);
  • 可拓展性(當須要添加新的功能時,很是的方便也稱爲可維護性);
  • 可靠性(當咱們添加新的功能後對原來的功能沒有影響);
  • 使程序呈現高內聚,低耦合等特性

迪米特原則

迪米特原則定義:git

  • 一個對象應該對其餘對象保持最少的瞭解
  • 類與類的關係越密切,耦合度越大
  • 迪米特法則還有個更簡單的定義:只與直接朋友通訊

迪米特法則又叫最少知道原則,即一個類對本身依賴的類知道的越少越好,也就是說,對於被依賴的類無論多複雜,都儘可能將邏輯封裝在類的內部,對外提供public方法,不對外泄露信息程序員

什麼是直接朋友:github

在一個類中:全局變量,返回值,參數傳遞就稱之爲直接朋友,編程

局部變量就稱之爲陌生朋友設計模式

來看一段通俗易懂的代碼:markdown

public class A {}
public class B {}
public class C {}
public class D {}
public class E {}

public class B {
   public A mA;

   public C getC(){
       return null;
   }

   public void showD(){
       D d = new D();
   }

   public void setA(E e){

   }
}
複製代碼

在B類中:app

  • public A mA; 全局變量
  • public C getC(){ 返回值
    return null;
    }
  • public void showD(){ 局部變量(違反迪米特原則)
    D d = new D();
    }
  • public void setA(E e){} 參數傳遞

在這裏A,C,E就是B的直接朋友,D就是B的陌生朋友框架

未遵照迪米特原則代碼:ide

public class Student{
    String name = "";
    public Student(String name) {
        this.name = name;
    }
}

public class StudentManager {
    public void getStudentNumber(Student student){
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(student.name+i);
            Log.i("dimiter:","如今是第 "+i+"個學生,名字爲: "+list.get(i));
        }
        Log.i("dimiter:","總共有 "+list.size()+"個學生 ");
    }
}

//使用代碼:
//迪米特原則
StudentManager studentManager = new StudentManager();
studentManager.getStudentNumber(new Student("張三"));
複製代碼

分析:

  • 學生類(Student) 有neme參數(學生姓名)
  • 學生管理類(StudentManager)建立10個學生,並輸出學生名字

違反迪米特原則代碼:

代碼圖(1.1):

\

爲何違反迪米特原則:

迪米特原則又叫作最少知道原則,首先要理解:

  • 何爲最少知道原則,意思就是:兩個類之間耦合性特別低,耦合性特別低就表明他們之間交互特別少,即一個類對本身依賴的類知道的越少越好,在代碼圖(1.1)這個例子中能夠看出,StudentManager()類對Studnet()類建立了10個學生名字.知道的太多了
  • 不對外泄露信息: 代碼圖(1.1)紅框的代碼,應該是在Student()內部完成,而後StudentManager()直接調用的

大白話解釋:StudentManager()須要全部學生,正確的應該是Student()吧全部學生直接給StudentManager(),而不是給一個Student()對象,讓StudentManager()本身去計算全部學生,在大白話一點就是:我問你要什麼你就給我什麼,不要讓我來計算(一個類對本身依賴的類知道的越少越好),你的東西也別讓我知道(不對外泄露信息)

仍是比較繞口,來看看遵照迪米特原則的代碼就直接恍然大悟了~

遵照迪米特原則:

public class Student{
    String name = "";///學生名字
    
     ///用來存儲全部學生名字
    ArrayList<String> mList = new ArrayList<>();

    public Student(String name) {
        this.name = name;
    }

     /// 遵照迪米特原則 建立10個學生
    public List<String> newStudentName(){
        for (int i = 0; i < 10; i++) {
            mList.add(name+i);
            Log.i("dimiter:","如今是第 "+i+"個學生,名字爲: "+mList.get(i));
        }
        return mList;
    }
}

public class StudentManager {
    public void getStudentNumber(Student student) {
        /// 遵照迪米特原則
        List<String> list = student.newStudentName();
        Log.i("dimiter:", "總共有 " + list.size() + "個學生 ");
    }
}

//使用代碼:
//迪米特原則
StudentManager studentManager = new StudentManager();
studentManager.getStudentNumber(new Student("張三"));
複製代碼

Student()建立10個學生,而後給到StudentManager()遵照了:

最少知道(迪米特)原則一個類對本身依賴的類知道的越少越好而且不對外泄露信息,

一個對象應該對其餘對象保持最少的瞭解

這裏的最少了解就是指10個Student()學生

我只知道你有10個學生,無論你這10個學生是怎麼來的

效果圖(2.1):

開閉原則

開閉原則定義:

  • 開閉原則是編程中最基礎,最重要的設計原則
  • 一個軟件實體如類,模塊和方法應該對拓展開放(對提供方),對修改關閉(對使用方),用抽象構建框架,用實現拓展細節(細節指實現代碼)
  • 當軟件需求要變化時,儘可能經過拓展軟件的實體的行爲來實現變化,而不是經過修改已有的代碼來實現變化
  • 遵照其餘原則,以及使用設計模式的目的就是遵照開閉原則

未遵照開閉原則代碼:

//形狀類型
public abstract class Shape {
    /** * 用來判斷類型 * 1:Circular 圓形 * 2:Rectangle 矩形 */
    int type;
}

//圓形
public class Circular extends Shape {
    public Circular() {
        type = 1;
    }
}

//矩形
public class Rectangle extends Shape {
    public Rectangle() {
        type = 2;
    }
}
//開閉原則Manager類 
public class OpenManager {
    public void showShape(Shape shape){
        if (shape .type == 1) {
            drawCircular(shape);
        }else if (shape.type == 2){
            drawRectangle();
        }
    }

    private void drawRectangle() {
        Log.i("Open","建立矩形 ");
    }
    private void drawCircular(Shape shape) {
        Log.i("Open","建立圓形 ");
    }
}

//使用代碼:
 //開閉原則
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());//建立圓
openManager.showShape(new Rectangle());//建立矩形 
複製代碼

效果圖(2.2):

爲何沒有遵照開閉原則:

開閉原則的最關鍵的定義是:

拓展開放(對提供方),對修改關閉(對使用方),用抽象構建框架,用實現拓展細節(細節指實現代碼)

若是說我如今要新加一個三角形我該怎麼作呢?

是這樣寫?

public class Triangle extends Shape{
    public Triangle() {
        type = 3;
    }
}

public class OpenManager {
    public void showShape(Shape shape){
        if (shape .type == 1) {
            drawCircular();//建立圓
        }else if (shape.type == 2){
            drawRectangle();//建立矩形
        }else if(shape.type == 3){
            drawTriangle();//建立三角形
        }
    }
    private void drawTriangle() {
        Log.i("Open","建立三角形 ");
    }
}
//使用代碼
//開閉原則
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());
openManager.showShape(new Rectangle());
openManager.showShape(new Triangle());
複製代碼

效果圖(2.3):

\

這樣寫不只在改的過程當中容易致使代碼的衝突,並且經過if else判斷

若是我有100個圖形呢?判斷100次嗎?

if lese if lese if lese if lese if lese if lese if lese if lese if lese if lese…?

這樣寫出錯率過高了,並且沒有遵照到拓展開放,修改關閉

遵照開閉原則代碼:

public abstract class Shape {
    public abstract void showShape();
}

public class Circular extends Shape {
    @Override
    public void showShape() {
        Log.i("Open","建立圓形 ");
    }
}

public class Triangle extends Shape{
    @Override
    public void showShape() {
        Log.i("Open","建立三角形 ");
    }
}

public class Rectangle extends Shape {
    @Override
    public void showShape() {
        Log.i("Open","建立矩形 ");
    }
}

public class OpenManager {
    public void showShape(Shape shape){
        //遵照開閉原則
        shape.showShape();
    }
}

//使用代碼:
//開閉原則
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());
openManager.showShape(new Rectangle());
openManager.showShape(new Triangle());
複製代碼

分析:

  • 能夠看出,即便如今新增長了一個三角形類(Triangle),只要繼承自Shape就能夠畫出來,並且不用if else來判斷,代碼邏輯很是清晰
  • 這纔是真正的對擴展開發,對修改關閉,即便我如今在增長一個橢圓形,我自須要繼承自Shape()而後輸出一下便可
public class Ellipse extends Shape{
    @Override
    public void showShape() {
        Log.i("Open","我是新建立的橢圓形哦");
    }
}
 //開閉原則
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());
openManager.showShape(new Rectangle());
openManager.showShape(new Triangle());
openManager.showShape(new Ellipse());//建立橢圓形
複製代碼

依賴倒置原則有點相似,只不過依賴倒置原則是經過接口來實現,開閉原則是經過抽象來實現.

合成複用原則

合成複用原則定義:

軟件複用時,要儘可能先使用組合或者聚合等關聯關係來實現,其次才考慮使用繼承關係來實現


一般類的複用分爲繼承複用和合成複用兩種,繼承複用雖然有簡單和易實現的優勢,但它也存在如下缺點

  • 繼承複用破壞了類的封裝性。由於繼承會將父類的實現細節暴露給子類,父類對子類是透明的,因此這種複用又稱爲「白箱」複用。
  • 子類與父類的耦合度高。父類的實現的任何改變都會致使子類的實現發生變化,這不利於類的擴展與維護。
  • 它限制了複用的靈活性。從父類繼承而來的實現是靜態的,在編譯時已經定義,因此在運行時不可能發生變化

大白話翻譯:
儘可能不要繼承,若是繼承的話子類與父類耦合度高,父類對於子類是透明的.不利於維護,若是非要複用的話可使用組合/聚合的方式.

不瞭解組合/聚合不要緊,下一章我會詳細介紹類與類之間的關係!

設計原則的核心思想

  • 找出應用中可能須要的變化之處,把他們獨立出來,不要和那些不須要變化的代碼混在一塊兒。
  • 面向接口編程,而不是針對實現編程。
  • 爲了交互對象之間的鬆耦合設計而努力。
  • 拓展開放(對提供方),對修改關閉(對使用方),用抽象構建框架,用實現拓展細節(細節指實現代碼)

迪米特(最少知道)原則代碼

開閉原則

設計模式總結:

  • 開閉(OCP)原則: 拓展開放,修改關閉
  • 接口隔離原則:類之間的依賴關係應該創建在最小的接口上
  • 單一職責原則:一個類負責一項職責,而不是一個類負責一個職責
  • 依賴倒置原則:面向接口編程
  • 里氏替換原則:在繼承時,在子類中儘可能不要去重寫父類的方法,若是非要使用,可使用聚合,組合,依賴來解決問題,不要修改父類的方法!
  • 迪米特(最少知道)原則:只與直接朋友通訊,一個類對本身依賴的類知道的越少越好,不對外泄露信息
  • 合成複用原則:要儘可能使用組合或聚合的關係來實現,其次在考慮繼承

猜你喜歡:

去設計模式/設計原則目錄頁

原創不易,記得點個贊哦~

相關文章
相關標籤/搜索