設計模式(總綱)

概念:設計模式是一套被反覆使用多數人知曉的、通過分類編目的、代碼設計經驗的總結。html

如下是對上面有下劃線的關鍵字的通俗解釋:程序員

  1. 反覆使用:在實際的開發中被使用的次數太多了,好比:單例模式、外觀模式、工廠模式等
  2. 多數人知曉:做爲一個程序員即便沒看過相關書籍不瞭解全部設計模式的具體內容也會知道一些很是常見的幾種設計模式,並且有些設計模式即便你不知道,在平常的代碼開發中也會使用。
  3. 分類編目:就是說能夠找到一些特徵去劃分這些設計模式,從而進行分類。
  4. 代碼設計經驗:代碼寫多了,就會積累代碼設計的經驗,設計模式就是從這些經驗中總結出來的用來解決一些特定場景中的問題的方法。

優勢:數據庫

  設計模式能夠幫助咱們改良項目的代碼,加強代碼的健壯性、可擴展性,爲之後開發和維護鋪平道路。有過開發經驗的人都知道一個項目的代碼設計好壞對以後開發的影響,特別是從事維護項目工做的人應該有更深的體會(雖然我並未從事過維護= 。=),能夠想象當一個看起來很簡單的需求,可是因爲項目設計問題,並無考慮到這個需求的變動時或則因爲需求不斷變動致使代碼變得臃腫,而致使當你修改其中一處可能致使其餘功能出現異常,加深了維護代碼的難度,這是一個很是嚴重的後果編程

注意點:設計模式

  設計模式是能夠改善項目的設計,但過多的使用甚至濫用將會致使項目變得複雜,難以讀懂。因此當咱們第一次設計一個系統時,請將你肯定的變化點處理掉,不肯定的變化點千萬不要假設它存在,若是你曾經這麼作過,那麼請改變你的思惟,讓這些虛無的變化點在你腦子中完全消失。由於咱們徹底可使用另一種方法來處理那些不肯定的變化點,那就是重構。至於重構等討論完設計模式後再進行探討。測試

六大原則:  this

  1. 單一職責原則

    概念:就一個類而言,應該僅有一個引發它變化的緣由spa

      描述的意思是每一個類都只負責單一的功能,切不可太多,而且一個類應當儘可能的把一個功能作到極致。若是一個類承擔的職責過多,就等於把這些職責耦合在一塊兒,這種耦合會致使脆弱的設計,即當其中一個職責發生變化時將會影響這個類完成其它職責的功能。如下代碼就沒有遵照該原則設計

    public class Calculator {
    
        public int add() throws Exception{ File file = new File("E:/data.txt"); BufferedReader br = new BufferedReader(new FileReader(file)); int a = Integer.valueOf(br.readLine()); int b = Integer.valueOf(br.readLine()); return a+b; } public static void main(String[] args) throws Exception { Calculator calculator = new Calculator(); System.out.println("result:" + calculator.add()); } }

      例子中的add方法擁有從文件中讀取數字和對數字進行加法運算的職責。這將會致使咱們若想增長一個減法運算的功能還得copy讀取文件職責,當運算增長時,將會照成大量重複的代碼。咱們用兩個類來實現這兩個職責。code

      用來讀取文件數據的類,以下代碼所示

    public class Reader {
        
        int a,b; public Reader(String path) throws Exception{ BufferedReader br = new BufferedReader(new FileReader(new File(path))); a = Integer.valueOf(br.readLine()); b = Integer.valueOf(br.readLine()); } public int getA(){ return a; } public int getB(){ return b; } }

      用來進行運算的類,代碼以下所示

    public class Calculator {
    
        public int add(int a,int b){ return a + b; } public static void main(String[] args) throws Exception { Reader reader = new Reader("E:/data.txt"); Calculator calculator = new Calculator(); System.out.println("result:" + calculator.add(reader.getA(),reader.getB())); } }

      將職責拆分後當咱們須要多個運算時就不會出現重複編寫讀取文件的代碼。

      以上例子是出自左瀟龍的博客,單一職責原則是我以爲六大原則當中最應該遵照的原則,在項目的開發過程當中遵循它,減小大量重複的代碼不會增長項目的複雜性,反而會令你的程序看起來井井有理。

    總結:在開發過程當中當發現有多於一個的動機會去改變一個類,那這個類就具備了多於一個的職責,就須要咱們考慮對該類的職責進行分離。

  2. 里氏替換原則

    概念:任何基類能夠出現的地方,子類必定能夠出現

          描述的意思是一個軟件實體若是使用的是一個父類的話,那麼必定適用於其子類,也就是說將程序中的父類替換爲子類,程序的行爲不會發生改變,若不遵照這個原則,當咱們須要將父類替換爲子類的時候還須要考慮是否會影響代碼的正常運行,如下代碼就沒有遵照這個原則
          父類代碼
    public class Parent {
    
        public void method() {
            System.out.println("執行 Parent.method()");
        }
    }

          子類代碼

    public class Children extends Parent {
    
        public void method() {
            System.out.println("執行 Children.method()");
            throw new RuntimeException();
        }
    }

         測試代碼

    public class Test {
    
        public static void main(String[] args) {
            new Parent().method();
            new Children().method();
        }
    }

            從以上代碼的運行結果能夠看出,當咱們將父類替換爲子類的時候就拋出了異常。要想不出現以上問題,最直接的辦法就是子類不要重寫父類的方法,可是在某些特定的場景重寫是不可或缺的,重寫的時候咱們須要進行判斷重寫帶來的好處是否大於它所形成的危害,如果也可適當的違反這個原則

    總結:有時候違反這個原則能讓咱們以失去一小部分的代價獲得不少,有時則相反,咱們若想活學活用,必須深入的理解這個原則的意義所在

  3. 接口隔離原則

    概念:客戶端不該該依賴它不須要的接口;一個類對另外一個類的依賴應該創建在最小的接口上

            描述的意思是一個接口擁有的功能應儘量的少,這樣當一個類實現該接口時,不須要實現那些沒用的方法,若違反這個原則每每會出現須要編寫一個空的方法來實現那些沒用的方法,而這會讓調用方認爲你有該功能,但真正調用時卻沒有的到想要的結果。若你不遵照這個原則,那你將有可能寫出以下接口
    public interface Mobile {
    
        public void call();//手機能夠打電話
        
        public void sendMessage();//手機能夠發短信
        
        public void playBird();//手機能夠玩憤怒的小鳥?
        
    }

            以上接口中的方法playBird明顯不是沒一個手機都應該有的功能,當一個非智能的手機實現這個接口時,因爲它並不能玩因此該方法只能空着,但調用方確發現非智能手機也有該方法,這就形成了誤解
            因此咱們應該新建一個智能手機的接口繼承手機接口並將playBird方法移動到智能手機接口中,這樣就不會出現以上問題,智能手機的接口代碼以下

    public interface SmartPhone extends Mobile{
    
        public void playBird();//智能手機能夠玩憤怒的小鳥
        
    }

    總結:遵照該原則能讓咱們實現一個接口時,不須要實現那些沒用的功能,也就不會給調用方形成假象

  4. 依賴倒置原則

    概念:高層模塊不該該依賴低層模塊,兩個都應該依賴抽象。抽象不該該依賴細節,反之細節應該依賴抽象     

           描述的意思是細節即實現會隨着場景的變化而發生改變,因此是不穩定的,反之抽象是穩定的,因此當依賴於抽象的時候不會由於其中一個實現的改變而影響另外一個
           上述單一職責原則中的計算器例子中,計算器就是依賴於數據讀取類的,這種編程就不太好。若咱們將從文件中讀取修改成數據庫,爲了避免影響計算器的代碼就必須將讀取類進行大量修改,固然咱們也能夠新增一個數據庫讀取的類DBReader並件計算器類中的全部Reader替換爲DBReader。當再增長多種讀取的方式,咱們就須要一個更好的作法去實現,即經過抽象出一個讀取的接口,代碼以下所示
    public interface Reader {
    
        public int getA();
        
        public int getB();
    }
    這樣咱們只須要建立不一樣讀取方法的類來實現該接口,這樣計算器類只要依賴於Reader接口就行,不須要知道數據是經過何種方方式讀取

    總結:在實際的編程中咱們應該讓客戶端調用接口,而不是調用具體的實現,這樣可讓咱們的程序更具備靈活性

  5. 迪米特法則

    概念:一個對象應當對其餘對象有儘量少的瞭解,不和其它類有太多接觸

           描述的意思是若一個類知道或者說是依賴於另一個類太多細節,這樣會致使耦合度太高,應該將細節所有高內聚於類的內部,其餘的類只須要知道這個類主要提供的功能便可,類之間的耦合越弱,越有利於複用,當其中一個處於弱耦合的類被修改,不會對有關係的類形成影響。若不遵照該法則你可能寫出以下代碼
    public class Reader {
        
        int a,b;
        
        private String path;
        
        private BufferedReader br;
        
        public Reader(String path){
            this.path = path;
        }
        
        public void setBufferedReader() throws FileNotFoundException{
            br = new BufferedReader(new FileReader(new File(path)));
        }
        
        public void readLine() throws NumberFormatException, IOException{
            a = Integer.valueOf(br.readLine());
            b = Integer.valueOf(br.readLine());
        }
        
        public int getA(){
            return a;
        }
        
        public int getB(){
            return b;
        }
    }

            這樣當客戶端須要獲取a和b的值時,須要寫成以下代碼所示

    public class Client {
    
        public static void main(String[] args) throws Exception {
            Reader reader = new Reader("E:/test.txt");  
            reader.setBufferedReader();                       
            reader.readLine();                                    
            int a = reader.getA();
            int b = reader.getB();
        }
    }

            以上代碼能夠看出咱們獲取a和b以前先調用了reader的setBufferedReader方法和readLine方法,這樣客戶端與Reader之間的耦合度就太高了,其實客戶端只須要獲取a和b的方法,並不須要知道Reader還有前兩個方法,咱們能夠將Reader類改爲以下所示

    public class Reader {
    
        int a,b;
        private String path;
        private BufferedReader br;
        public Reader(String path) throws Exception{
            super();
            this.path = path;
            setBufferedReader();
            readLine();
        }
        //注意,咱們變爲私有的方法
        private void setBufferedReader() throws FileNotFoundException{
            br = new BufferedReader(new FileReader(path));
        }
        //注意,咱們變爲私有的方法
        private void readLine() throws NumberFormatException, IOException{
            a = Integer.valueOf(br.readLine());
            b = Integer.valueOf(br.readLine());
        }
        
        public int getA(){
            return a;
        }
        
        public int getB(){
            return b;
        }
    }
            這樣客戶端想要獲取a或b,只須要調用對應的get方法,並不知道還有其它的方法

    總結:儘量將一個類的細節所有寫在這個類的內部,不要漏出來給其餘類知道,即儘可能下降類中成員的訪問權限,實現高內聚低耦合

  6. 開閉原則

    概念:對於擴展是開放的,對於修改是關閉的       

           開閉原則是面向對象設計的核心。儘可能的遵照這個規則能夠實現代碼的可維護、可擴展、可複用、靈活性好,在平常的開發中咱們應該對那些常常發生改變的部分進行抽象,但也不能刻意對各個部分進行抽象,防止不成熟的抽象和抽象自己同樣重要。
           當咱們的程序遵照了前5個規則,那麼這個程序也就比較符合這個原則

    總結:當需求修改或新增時,最好都是經過新增代碼進行實現,而不是修改現有的代碼

相關文章
相關標籤/搜索