1. 程式人生 > >設計模式(單例模式,工廠模式,介面卡模式)

設計模式(單例模式,工廠模式,介面卡模式)

1:設計模式是什麼?

前人總結的一些經驗和思想,給我們提供了從抽象到具體的方法

總共有23種
    分類:
        建立型模式: 建立物件。(其實建立物件比較耗記憶體的動作)
        結構型模式: 物件的組成。
        行為模式: 物件能夠做什麼。

    工廠模式:
        通過一個工廠類來幫我們建立物件

    單例模式:
        要求:類在記憶體中的物件只有一個。
        eg:印表機,網站訪問計數器。
    如何實現單例設計模式:
        分析:
            1:讓外界不能通過構造方法建立物件。
                將構造方法私有化。
            2:類本身要建立一個物件
                在成員位置建立一個物件
            3:對外提供一個公共的方法可以獲取該物件
    package com.thread.module;

public class Student {
    //1:建構函式初始化為私有,防止外界直接通過建構函式建立物件
    private Student() {

    }

    //6:由於靜態只能訪問靜態,此處也加上static
    //7:為了不讓外界直接訪問加上 private
    //2:提供一個物件
    private static Student s = new Student();

    //3:為了保證外界能夠獲取到物件,提供給外界的一個方法,
    //4:但是此時還是訪問不到。因為該方法沒有加static只能通過物件獲取
//5:為了能通過類名獲取,加入static public static Student getStudent() { return s; } }

static修飾,隨著類的載入就載入

    單例模式分類:
        餓漢式:
            一載入就建立物件(private static Student s = new
             Student();)  
             就是上面的程式碼。
        懶漢式:
            用的時候才去建立
            public static
Student1 getStudent1() { if (s == null) { s = new Student1(); } return s; }
package com.thread.module;

/**
 * 懶漢式
 */
public class Student1 {
    private Student1() {
    }

    private static Student1 s = null;

    public static Student1 getStudent1() {
        if (s == null) {
            s = new Student1();
        }
        return s;
    }

    public void show() {
        System.out.println("懶漢式");
    }
}
我們要掌握哪種方式呢?
    開發:餓漢式
    面試:懶漢式
為什麼?
    因為餓漢式不會出現執行緒安全問題。
    懶漢式:
        延遲載入思想:(懶載入思想)伺服器啟動的時候載入的資源會少一點
        執行緒不安全,你要給別人分析出安全問題的原因,並提供解決方案。
            /**
     * 此程式碼會產生執行緒安全問題
     * 當有四個執行緒呼叫該方法
     * t1,t2,t3,t4
     * @return
     */
    //5:解決:改為同步方法加synchronized
    public synchronized static Student1 getStudent1() {
        //1:t1,t2,t3,t4都進來了
        if (s == null) {
            //2:t1剛進入這裡,執行權就被t2搶到了,t2也進來了,同樣,t3,t4都進來了
            //3:四個執行緒都建立了物件,導致執行緒不安全(雖然最後返回的就只有一個物件)
            s = new Student1();
        }
        return s;
    }

Runtime類本身就是一個餓漢式的體現,通過檢視原始碼可知。

 public class Runtime{  
       private Runtime(){}  
       private static Runtime currentRuntime = new Runtime();  
      public static Runtime getRuntime(){  
          return currentRuntime;  
       }  
  }  
  //測試Runtime
public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        Runtime r = Runtime.getRuntime();
        //可以調用出path路徑中配置過的exe檔案
        r.exec("notepad");
    }
}

介面卡模式

    /**
    *場景:
        介面:Inter中有多個抽象方法
        普通類:有一個方法,方法的形參是Inter介面
            public void show(Inter i){}
        測試類:建立普通類的物件呼叫方法。
    */
    package com.thread.module;

/**
 * 介面中的方法都是抽象的,不管你加沒加abstract,沒有加預設就adstract
 * 
 */
public interface Inter {
    public abstract void show();
    public abstract void show1();
    public abstract void show2();
    public abstract void show3();
}

public class InterDemo {
    //方法的形式引數如果是介面,那麼傳遞的時候肯定是介面的子類物件,這就是多型。
    public void show(Inter i) {
        i.show3();
    }
}

public class InterTest {
    public static void main(String[] args) {
        InterDemo id = new InterDemo();
        id.show(new Inter() {

            @Override
            public void show3() {
                System.out.println("show3");
            }

            @Override
            public void show2() {
                System.out.println("show2");
            }

            @Override
            public void show1() {
            }

            @Override
            public void show() {
            }
        });
    }
}

在上面發現一個弊端。
在寫測試方法的時候,建立匿名Inner內部類的時候,會將所有的方法都重寫,這樣導致程式碼非常的難看,以及不簡介
改善:

    怎麼實現?
        介面中有多個方法
        然後來一個抽象方法去實現這個介面。而且提供的都是空實現
        最後在使用的時候,只需要重寫需要使用的那個方法就可以了。
        package com.thread.module;

public abstract class InterAdapter implements Inter {

    @Override
    public void show() {
    }

    @Override
    public void show1() {
    }

    @Override
    public void show2() {
    }

    @Override
    public void show3() {
    }

}

//InterTest中修改
    id.show(new InterAdapter() {
            @Override
            public void show3() {
                System.out.println("show3");
            }
        });