建立型模式
- 單例模式、工廠模式、抽象工廠模式、建造者模式、原型模式
結構型模式
- 適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式
行爲型模式
- 模板方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式、狀態模式、策略模式、職責鏈模式、訪問者模式。設計模式
核心做用:保證一個類只有一個實例,而且提供一個訪問該實例的全局訪問點。安全
單例模式優勢:因爲單例模式只生成一個實例,減小系統性能開銷,當一個對象的產生須要比較多的資源時,如讀取配置文件,則能夠經過在應用啓動時直接產生一個單例對象,而後永久駐留在內存的方式解決。多線程
常見的五種單例模式實現方式:併發
餓漢式(線程安全,調用效率高。可是不能延時加載)性能
懶漢式(線程安全,調用效率不高。可是能夠延時加載)測試
雙層檢測鎖式(因爲JVM底層內部模型緣由,偶爾出現問題,不建議使用)spa
靜態內部類式(線程安全、調用效率高,能夠延時加載)線程
枚舉單例(線程安全,調用效率高,不能延時加載,自然的防止反射和反序列化漏洞)設計
一、餓漢式代理
/** * 餓漢式單例模式 * static 變量會在類加載時初始化。JVM保證只會加載一次該類, 確定不會發生併發訪問的問題 */
public class SingleDemo1 { // 類初始化時加載這個對象
private static /*final*/ SingleDemo1 INSTANCE = new SingleDemo1(); // 構造方法私有
private SingleDemo1() {}
// 方法沒有同步, 調用效率高 public static SingleDemo1 getInstance() { return INSTANCE; } }
二、懶漢式
/** * 懶漢式 * 延時加載, 資源利用率高; * getInstance() 增長同步方法, 調用效率低 */
public class SingleDemo2 { private static SingleDemo2 singleDemo2; // 構造方法私有化
private SingleDemo2() {} // 加synchronized方法同步, 調用效率低
public static synchronized SingleDemo2 getInstance() { if(null == singleDemo2) { singleDemo2 = new SingleDemo2(); } return singleDemo2; } }
三、雙重檢測鎖模式
四、靜態內部類實現單例模式
/** * 靜態內部類實現單例模式 * 線程安全, 懶加載, 調用效率高 */
public class SingleDemo3 { // 靜態內部類
private static class SingleDemoInner { //類初始化時加載, static final 保證內存中只有一個這樣實例存在, 並且只能被賦值一次
private static final SingleDemo3 INSTANCE = new SingleDemo3(); } // 構造方法私有化
private SingleDemo3() {} // 沒有同步, 調用效率高
public static SingleDemo3 getInstance() { return SingleDemoInner.INSTANCE; } }
五、枚舉類
/** * 枚舉類實現單例模式 (不能延時加載) * 枚舉是自然的單例, 由JVM從根本上提供保障; * 避免經過反射和反序列化的漏洞! */
public enum SingleDemo4 { // 定義一個枚舉的元素, 它就表明了Singleton的一個實例
INSTANCE; //單例能夠有本身的操做
public void singletonOperation() { //功能處理
} }
六、使用反射或反序列化能夠破解上面的懶漢式、餓漢式、雙重檢測鎖模式(不建議使用)、靜態內部類式實現的單例。
(1)測試反射破解:
/** * 測試反射破解 */
public class MainTest { public static void main(String[] args) throws Exception { // 經過反射方式構造多個對象
Class<SingleDemo1> clazz = (Class<SingleDemo1>) Class.forName("com.yufeng.single.SingleDemo1"); Constructor<SingleDemo1> constructor= clazz.getDeclaredConstructor(null); constructor.setAccessible(true); //跳過權限檢查
SingleDemo1 demo3 = constructor.newInstance(); SingleDemo1 demo4 = constructor.newInstance(); System.out.println(demo3); System.out.println(demo4); } }
結果:
com.yufeng.single.SingleDemo1@14ae5a5
com.yufeng.single.SingleDemo1@7f31245a
(2)測試反序列化破解(SingleDemo1 實現 Serializable 接口)
/** * 測試反序列化破解 */
public class MainTest { public static void main(String[] args) throws Exception { // 經過反序列化構造多個對象
SingleDemo1 a1 = SingleDemo1.getInstance(); //序列化的類要實現 Serializable 接口 System.out.println(a1); //序列化
FileOutputStream fos = new FileOutputStream("d:/a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(a1); oos.close(); fos.close(); //反序列化
FileInputStream fis = new FileInputStream("d:/a.txt"); ObjectInputStream ois = new ObjectInputStream(fis); SingleDemo1 a2 = (SingleDemo1) ois.readObject(); System.out.println(a2); } }
解決反射和反序列化破解單例的問題
以懶漢式爲例,以下:
/** * 解決反射和反序列化破解單例的問題 */
public class SingleDemo5 implements Serializable { private static /*final*/ SingleDemo5 INSTANCE = new SingleDemo5(); // 構造方法私有
private SingleDemo5() { //防止反射破壞單例 能夠在構造方法中手動拋出異常,解決反射破解的問題
if(null != INSTANCE) { throw new RuntimeException("單例模式, 不可以使用反射建立實例."); } } // 方法沒有同步, 調用效率高
public static SingleDemo5 getInstance() { return INSTANCE; }
// 能夠經過readResolve()方法防止反序列得到到不一樣的對象 // 反序列化時, 若定義了readReolve()方法, 直接返回此方法指定的對象, 而不須要再單首創建新對象
private Object readResolve() throws ObjectStreamException { return INSTANCE; } }