天天看點

厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>開閉原則依賴倒置單一職責

厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>

開閉原則

定義

一個軟體實體如類、子產品和函數應該對擴充開放,對修改關閉。其優點:提高軟體系統的可複用性及可維護性

用抽象建構架構,用實作擴充細節,實作 面向抽象程式設計。

中心思想:抽象建構架構,實作擴充細節

場景舉例Coding

線上課程購買例子,課程線上購買:

厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>厚積薄發打卡Day113:Debug設計模式:設計原則(一)&lt;開閉原則、依賴倒置、單一職責&gt;開閉原則依賴倒置單一職責
/**
 * 課程接口
 */
public interface ICourse {
    // 課程id
    Integer getId();

    // 課程名字
    String getName();

    // 課程價格
    Double getPrice();
}
           
/**
 * Java課程
 */
public class JavaCourse implements ICourse {
    private Integer Id;
    private String name;
    private Double price;

    public JavaCourse(Integer id, String name, Double price) {
        Id = id;
        this.name = name;
        this.price = price;
    }

    @Override
    public Integer getId() {
        return this.Id;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Double getPrice() {
        return this.price;
    }
}
           

測試類:

public class Test {
    public static void main(String[] args) {
        ICourse course = new JavaCourse(1415, "Java企業級别開發", 299d);
        System.out.printf("課程id: %d,課程名稱:%s,課程價格:%f 元\n", course.getId(), course.getName(), course.getPrice());
    }
}
           
課程id: 1415,課程名稱:Java企業級别開發,課程價格:299.000000 元
           

場景變更:現在遇到活動,線上課程通通八折!那應該怎麼修改呢?

~~修改接口?~~那會影響全部實作類,如果有一個實作類則修改一個實作類,那如果實作類很多是否都需要一個個進行修改呢?

**軟體開發設計重點:接口不應該輕易修改,穩定且可靠,作為契約。**同時,越底層的子產品變化影響越大,越高層的子產品變化影響則越小。

那不在影響原有代碼的基礎上進行擴充,最好的方法就是使用Java的多态特性:繼承。

場景實作:

厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>厚積薄發打卡Day113:Debug設計模式:設計原則(一)&lt;開閉原則、依賴倒置、單一職責&gt;開閉原則依賴倒置單一職責
public class DiscountCourse extends JavaCourse {
    public DiscountCourse(Integer id, String name, Double price) {
        super(id, name, price);
    }

    public Double getOriginPrice() {
        return super.getPrice();
    }


    public Double getDiscountPrice() {
        // 同時這裡可以對折扣價格方案進行處理
        return super.getPrice() * 0.8;
    }
}
           

測試類:

public class Test {
    public static void main(String[] args) {
        ICourse course = new JavaCourse(1415, "Java企業級别開發", 299d);
        System.out.printf("課程id: %d,課程名稱:%s,課程價格:%f 元\n", course.getId(), course.getName(), course.getPrice());

        DiscountCourse course2 = new DiscountCourse(1415, "Java企業級别開發", 299d);
        System.out.printf("課程id: %d,課程名稱:%s,課程原始價格:%f 元,618活動折扣價為:%f 元\n", course2.getId(), course2.getName(), course2.getOriginPrice(), course2.getDiscountPrice());
    }
}
           
課程id: 1415,課程名稱:Java企業級别開發,課程價格:299.000000 元
課程id: 1415,課程名稱:Java企業級别開發,課程原始價格:299.000000 元,618活動折扣價為:239.200000 元
           

這樣通過繼承的方式,不改變原有代碼的基礎上,實作了折扣價方案的修改實作。

依賴倒置

定義:

  • 高層子產品不應該依賴低層子產品,二者都應該依賴其抽象。
  • 抽象不應該依賴細節;細節應該依賴抽象
  • 核心思想:針對接口程式設計,面向接口程式設計,不要針對實作程式設計

優點:

  • 可以減少類間的耦合性、提高系統穩定性,提高代碼可讀性和可維護性,可降低修改程式所造成的風險

場景Coding:

  • 舉例:面向實作類程式設計
    public class Wayne {
        public void studyJavaCourse(){
            System.out.println("Wayne在學習Java課程");
        }
        public void studyPythonCourse(){
            System.out.println("Wayne在學習Python課程");
        }
    }
               
    public class Test {
        public static void main(String[] args) {
            // v1
            Wayne wayne = new Wayne();
            wayne.studyJavaCourse();
            wayne.studyPythonCourse();
        }
    }
               
    Wayne在學習Java課程
    Wayne在學習Python課程
               
    • 此時Test是應用層,Wayne是底層子產品,如果這時候wayne要學習更多課程,則在底層子產品進行修改,違背了

      高層子產品不應該依賴低層子產品

      ,直接引用了而不是通過抽象依賴。
  • 引用抽象
    厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>厚積薄發打卡Day113:Debug設計模式:設計原則(一)&lt;開閉原則、依賴倒置、單一職責&gt;開閉原則依賴倒置單一職責
    // 抽象依賴
    public interface IStudy {
        void studyCourse();
    }
               
    依賴實作:
    public class GoStudy implements IStudy {
        @Override
        public void studyCourse() {
            System.out.println("Wayne在學習Go語言");
        }
    }
               
    public class JavaStudy implements IStudy{
        @Override
        public void studyCourse() {
            System.out.println("Wayne在學習Java");
        }
    }
               
    public class PythonStudy implements IStudy {
        @Override
        public void studyCourse() {
            System.out.println("Wayne在學習Python");
        }
    }
               
    底層:
    public class Wayne {
        public void studyCourse(IStudy study) {
            study.studyCourse();
        }
    }
               
    應用層:
    public class Test {
        public static void main(String[] args) {
            //v2
            Wayne wayne = new Wayne();
            wayne.studyCourse(new PythonStudy());
            wayne.studyCourse(new JavaStudy());
            wayne.studyCourse(new GoStudy());
        }
    }
               
    Wayne在學習Python
    Wayne在學習Java
    Wayne在學習Go語言
               
  • 使用構造器注入(單例模式):有點Spring的味道了
public class Wayne {
    // ---單例:
    private IStudy iStudy;

    public Wayne(IStudy iStudy) {
        this.iStudy = iStudy;
    }

    public void studyCourse() {
        iStudy.studyCourse();
    }
}
           
//v3:單例模式:
new Wayne(new JavaStudy()).studyCourse();
new Wayne(new PythonStudy()).studyCourse();
           
  • set方法注入:注入方式無需修改底層子產品,即後續想要學習什麼課程直接擴充IStudy即可。
    public class Wayne {
        // set注入
        private IStudy iStudy;
    
        public void setiStudy(IStudy iStudy) {
            this.iStudy = iStudy;
        }
        public void studyCourse() {
            iStudy.studyCourse();
        }
    }
               
    //v4:set注入
        Wayne wayne = new Wayne();
        wayne.setiStudy(new JavaStudy());
        wayne.studyCourse();
    
        wayne.setiStudy(new GoStudy());
        wayne.studyCourse();
               
    綜上總結:面向接口程式設計

單一職責

定義:

不要存在多于一個導緻類變更的原因,一個類/接口/方法隻負責一項職責

優點:降低類的複雜度、提高類的可讀性,提高系統的可維護性、降低變更引起的風險

場景Coding

  • 場景耦合
    public class Bird {
        public void mainMoveMode(String birdName) {
            //使用邊界判斷
            if ("鴕鳥".equals(birdName)) {
                System.out.println(birdName + "用腳走");
            } else {
                System.out.println(birdName + "用翅膀飛");
            }
        }
    }
               
    public class Test {
        public static void main(String[] args) {
            Bird bird = new Bird();
            bird.mainMoveMode("鴕鳥");
            bird.mainMoveMode("大雁");
            bird.mainMoveMode("鴿子🕊");
        }
    }
               
    鴕鳥用腳走
    大雁用翅膀飛
    鴿子🕊用翅膀飛
               
    如果後面增加飛行動物,則需要不斷修改Bird裡面的代碼,同時功能并不單一,違背單一職責原則。
  • 類擴充,實作單一原則
厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>厚積薄發打卡Day113:Debug設計模式:設計原則(一)&lt;開閉原則、依賴倒置、單一職責&gt;開閉原則依賴倒置單一職責
public class FlyBird {
    public void mainMoveMode(String birdName){
        System.out.println(birdName+"用翅膀飛");
    }
}
           
public class WalkBird {
    public void mainMoveMode(String birdName){
        System.out.println(birdName+"用腳走");
    }
}
           
public class Test {
    public static void main(String[] args) {
        WalkBird walkBird = new WalkBird();
        walkBird.mainMoveMode("鴕鳥");

        FlyBird flyBird = new FlyBird();
        flyBird.mainMoveMode("大雁");
    }
}
           
鴕鳥用腳走
大雁用翅膀飛
           
  • 接口擴充,以課程舉例
    public interface ICourse {
        // 課程内容管理
        String getCourseName();
        byte[] getCourseVideo();
    
        // 課程中心管理
        void studyCourse();
        void refundCourse();
    }
               
    接口在實作類中進行細分:
厚積薄發打卡Day113:Debug設計模式:設計原則(一)<開閉原則、依賴倒置、單一職責>厚積薄發打卡Day113:Debug設計模式:設計原則(一)&lt;開閉原則、依賴倒置、單一職責&gt;開閉原則依賴倒置單一職責
public interface ICourseContent {
    String getCourseName();
    byte[] getCourseVideo();
}
           
public interface ICourseManager {
    void studyCourse();
    void refundCourse();
}
           
public class CourseImpl implements ICourseManager, ICourseContent {
    @Override
    public void studyCourse() {
    }

    @Override
    public void refundCourse() {
    }

    @Override
    public String getCourseName() {
        return null;
    }

    @Override
    public byte[] getCourseVideo() {
        return new byte[0];
    }
}
           
  • 方法級别,單一職責,方法一般通過對象實作,酌情參考。
    public class Method {
        private void updateUserInfo(String userName, String address) {
            userName = "wayne";
            address = "beijing";
        }
    
        private void updateUserInfo(String userName, String... properties) {
            userName = "wayne";
    //        address = "beijing";
        }
    
        private void updateUsername(String userName) {
            userName = "wayne";
        }
    
        private void updateUserAddress(String address) {
            address = "beijing";
        }
    
        private void updateUserInfo(String userName, String address, boolean bool) {
            if (bool) {
                //todo something1
            } else {
                //todo something2
            }
            userName = "wayne";
            address = "beijing";
        }
    }
               

總結:單一職責會新增很多類,若盲目使用則會造成類爆炸要根據實際情況,盡量做到接口和方法的單一職責