GOF23設計模式之單例模式

GOF23設計模式(Group Of Four)

爲國外頗有名的四個大牛總結的23總常見的套路html

分類:

1)建立型模式

單例模式、工廠模式、抽象工廠模式、建造者模式、原型模式java

2)結構型模式

適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式設計模式

3)行爲型模式

模板方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式、狀態模式、策略模式、職責鏈模式、訪問者模式安全

 

單例模式

核心做用:保證一個類只有一個實例,而且提供一個訪問該實例的全局訪問點性能

單例模式的優勢:

因爲單例模式只生成一個實例,減小了系統性能開銷。測試

單例模式能夠在系統設置全局的訪問點,優化共享資源訪問。例如能夠設計一個單例類,負責全部數據表的映射處理。優化

常見的五種單例模式的實現方式:

主要:

餓漢式(線程安全,調用效率高。可是,不能延時加載。)spa

package cn.taosir.design.create.singleton;

/**
 * 餓漢式
 * @author taosir
 *
 */
public class HungryType {

    //類初始化時當即加載(不具有延時加載的優點),因爲加載類時自然是線程安全的
    private static HungryType hungryType=new HungryType();
    
    //構造方法私有化
    private HungryType() {};
    
    //開放方法供外部提取實例,方法不須要同步,調用效率高
    public static HungryType getInstance() {
        return hungryType;
    }
}

懶漢式(線程安全,調用效率不高。可是,能夠延時加載。)線程

package cn.taosir.design.create.singleton;
/**
 * 懶漢式
 * @author taosir
 *
 */
public class LazyType {
    
    //類初始化時,不初始化這個對象(延時加載,真正須要的時候才建立實例)
    private static LazyType lazyType;
    
    //構造方法私有化
    private LazyType() {};
    
    //方法同步,調用效率低
    public static synchronized LazyType getInstance() {
        if(lazyType==null)
            lazyType=new LazyType();
        return lazyType;
    }
}

其餘:

雙重檢測鎖式(因爲JVM底層內部模型緣由,偶爾會出現問題,不建議使用)設計

靜態內部類式(線程安全,調用效率高。可是,能夠延時加載,結合了餓漢式和懶漢式的優勢)

package cn.taosir.design.create.singleton;
/**
 * 靜態內部類實現
 * @author taosir
 *
 */
public class StaticInner {

    //使用一個靜態的內部類來建立實例,當使用下面的StaticInnerInstance.staticInner時纔會初始化
    private static class StaticInnerInstance{
        private static final StaticInner staticInner=new StaticInner();
    }
    
    //方法沒有同步,調用效率高
    public static StaticInner getInstance() {
        return StaticInnerInstance.staticInner;
    }
    
    //私有化構造方法
    private StaticInner() {}
}

枚舉單例(線程安全、調用效率高,不能延時加載)

package cn.taosir.design.create.singleton;
/**
 * 枚舉單例
 * @author taosir
 *
 */
public enum Enumeration {

    //這個枚舉元素自己就是單例
    INSTANCE;
    
    //添加本身須要的操做
    public void doYouWantToDo() {
        
    }
}

 使用反射和反序列化破解單利模式及如何防止破解

  破解單例模式的方法

package cn.taosir.design.create.singleton;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;

/** 
 * * 測試反射和反序列化破解單利模式
 * @author Administrator
 *
 */
public class CrackDemo {
    public static void main(String[] args) throws Exception {
        
        
        LazyType4Crack lazy=LazyType4Crack.getInstance();
        
        //反射
//        Class<LazyType4Crack> clazz=(Class<LazyType4Crack>)Class.forName("cn.taosir.design.create.singleton.LazyType4Crack");
//        Constructor<LazyType4Crack> constructor=clazz.getDeclaredConstructor(null);
//        constructor.setAccessible(true);//此方法能夠跳過權限的檢查,破解單例
//        LazyType4Crack lazyOne=constructor.newInstance();
//        System.out.println(lazy);
//        System.out.println(lazyOne);
//        System.out.println(lazy==lazyOne);
        
        //序列化
        FileOutputStream fos=new FileOutputStream("./a.txt");
        ObjectOutputStream ooStream=new ObjectOutputStream(fos);
        ooStream.writeObject(lazy);
        ooStream.close();
        fos.close();
        //反序列化
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("./a.txt"));
        LazyType4Crack layCrack=(LazyType4Crack)ois.readObject();
        System.out.println(lazy==layCrack);
    }
}
 

防止破解的方法(以懶漢式爲例)

package cn.taosir.design.create.singleton;

import java.io.Serializable;

/**
 * * 懶漢式(如何防止反射和反序列化漏洞)
 * @author taosir
 *
 */
public class LazyType4Crack implements Serializable{

    //類初始化時,不初始化這個對象(延時加載,真正須要的時候才建立實例)
    private static LazyType4Crack lazyType4Crack;

    //構造方法私有化
    private LazyType4Crack() {
     //防止反射
if(lazyType4Crack!=null) { throw new RuntimeException(); } } //方法同步,調用效率低 public static synchronized LazyType4Crack getInstance() { if(lazyType4Crack==null) lazyType4Crack=new LazyType4Crack(); return lazyType4Crack; } //反序列化時,若是定義了readResolve()則直接返回此方法指定的對象。而不須要單獨再建立新對象 private Object readResolve() { return lazyType4Crack; } }
相關文章
相關標籤/搜索