設計模式---六大設計原則

2022-09-20 06:04:05

六大設計原則

  1. 單一職責原則
  2. 介面隔離原則
  3. 開閉原則
  4. 依賴倒置原則
  5. 里氏代換原則
  6. 迪米特法則

單一職責原則

我們分別看兩個案例,一個是遵守單一職責原則,另一個是違背。

違背的案例

class Computer {
    void calc() {
        System.out.println("計算資料"); // 基本功能,麼得問題
    }
    void display() {
        System.out.println("顯示計算結果"); // 現在的計算機確實有顯示功能
    }
    void run() {
        System.out.println("以百米衝刺的速度奔跑"); // 這什麼玩意兒?這個類到底是幹嘛的
    }
}

遵守的案例

class Computer {
    void calc() {
        System.out.println("計算資料"); // 基本功能,麼得問題
    }
    void display() {
        System.out.println("顯示計算結果"); // 現在的計算機確實有顯示功能
    }
}
class Humam {
    void run() {
        System.out.println("以百米衝刺的速度奔跑"); // 人會跑不是很正常嘛
    }
}

單一職責的核心:限制類的職責範圍,杜絕功能複雜的類的產生
介面隔離原則也是同樣的思想,就不廢話了。

開閉原則

class Style {
    public void set() {
        System.out.println("設定圓角");
    }
}

當需要改變樣式的時候。不遵守開閉原則的做法。

class Style {
    public void set() {
        // System.out.println("設定圓角");
        System.out.println("設定order");
        /* 
        	直接修改原有的方法上做修改
         */
    }
}

而遵守開閉原則的做法。

// 將原有的Style類抽象成介面,這樣對使用者端也沒有影響,
// 因為用的還是Style並沒有改名,只是原來是個類,現在變成了介面
interface Style {
    void set();
}
class Radius implements Style {
    public void set() {
        System.out.println("設定圓角");
    }
}
class Order implements Style { // 不對原有的實現類修改,而是增加一個新個實現類
    public void set() {
         System.out.println("設定order");
    }
}

開閉原則的核心:對修改關閉,對拓展開放
不在原有的程式碼上增減新的程式碼,而是新增新的模組。核心要點是面向介面程式設計。

依賴倒置原則

不符合依賴倒置原則的案例。

class Radius {
    public void set() {
        System.out.println("設定圓角");
    }
}
class Order {
    public void set() {
        System.out.println("設定order");
    }
}
class Client {
    public void setRadius(Radius radius) {
        adius.set();
    }
    public void setOrder(Order order) {
        rder.set();
    }
}

符合依賴倒置原則的案例。

interface Style {
    void set();
}
class Radius implements Style {
    public void set() {
        System.out.println("設定圓角");
    }
}
class Order implements Style {
    public void set() {
        System.out.println("設定order");
    }
}
class Client {
    public void setStyle(Style style) {
        style.set();
    }
}

依賴倒置的核心:從依賴具體類變為依賴抽象或介面。面向介面程式設計。

里氏代換原則

不符合里氏代換原則的案例。

class CacheCard {
    protected int balance;
    public void peek() {
        System.out.println("餘額:" + balance);
    }
    public void deposit(int num) {
        balance += num;
        System.out.println("存款金額:" + num);
        peek();
    }
    public void withdraw(int num) {
        balance += num;
        System.out.println("取款金額:" + num);
        peek();
    }
}
class CreditCard extends CacheCard {
    public void deposit(int num) { // 信用卡並沒有存錢這個功能,不應該重寫
        balance += num;
        System.out.println("還款金額:" + num);
        peek();
    }
    public void withdraw(int num) { // 也沒有取款的功能,不應該重寫
        balance += num;
        System.out.println("支付金額:" + num);
        peek();
    }
}

符合里氏代換原則的案例。

interface BankCard {
    int balance;
    default void peek() {
        System.out.println("餘額:" + balance);
    }
    void positive(int num);
    void negative(int num);
}
class CacheCard implements BankCard {
    public void positive(int num) {
        balance += num;
        System.out.println("存款金額:" + num);
        peek();
    }
    public void negative(int num) {
        balance -= num;
        System.out.println("取款金額:" + num);
        peek();
    }
}
class CreditCard implements BankCard {
    public void positive(int num) {
        balance += num;
        System.out.println("還款金額:" + num);
        peek();
    }
    public void negative(int num) {
        balance -= num;
        System.out.println("支付金額:" + num);
        peek();
    }
}

里氏代換原則的核心思想:使用父類別能夠實現的功能,使用其子類依舊能實現。限制方法重寫的範圍,從業務的角度出發我們只可以重寫父類別中被允許重寫的方法,而不是從Java語法角度(那能重寫的多了去了)出發重寫方法。

迪米特法則

不符合迪米特法則的案例。

class Student {
    String name;
    String sex;
    int score;
}
class Teacher {
    String name;
    String sex;
    Student[] students;
    int max() {
        int res = 0;
        for (student : students) {
            res = Math.max(res, student.score);
        }
        return res;
    }
    int min() {
        int res = 0;
        for (student : students) {
            res = Math.min(res, student.score);
        }
        return res;
    }
}
class President {
    String name;
    String sex;
    Student[] students; // 不應該依賴Student類,而應該依賴Teacher類,將所有對於students的操作封裝到Teacher類中
    Teacher[] teachers;
    int avg() { // 這個方法應該在Teacher中定義
        int res = 0;
        for (student : students) {
            res += student.score;
        }
        return res / students.length;
    }
    String[] teachersName() { // 獲取所有的老師名字
        String[] res = new String[teachers.length];
        for (int i = 0; i < res.length; i ++) {
            res[i] = teachers[i].name;
        }
        return res;
    }
}

符合迪米特法則的案例。

class Student {
    String name;
    String sex;
    int score;
}
class Teacher {
    String name;
    String sex;
    Student[] students;
    int max() {
        int res = 0;
        for (student : students) {
            res = Math.max(res, student.score);
        }
        return res;
    }
    int min() {
        int res = 0;
        for (student : students) {
            res = Math.min(res, student.score);
        }
        return res;
    }
    int avg() { // 這個方法應該在Teacher中定義
        int res = 0;
        for (student : students) {
            res += student.score;
        }
        return res / students.length;
    }
}
class President {
    String name;
    String sex;
    Teacher[] teacher; // 依賴Teacher類
    int[] avgs() { // 獲取每個班級的平均分
        int[] res = new int[teacher.length];
        for (int i = 0; i < res.length; i ++) {
            res[i] = teacher[i].avg(); // 實際計算呼叫Teacher內的計算
        }
        return res;
    }
    String[] teachersName() { // 獲取所有的老師名字
        String[] res = new String[teachers.length];
        for (int i = 0; i < res.length; i ++) {
            res[i] = teachers[i].name;
        }
        return res;
    }
}

迪米特法則的核心思想:最少知道,最少依賴。類的定義應當把對於其他類的依賴降到最低。
遵守迪米特法則的同時也基本滿足了單一職責原則。