GOF23设计模式之单例模式

GOF23设计模式(Group Of Four)

为国外很有名的四个大牛总结的23总常见的套路

分类:

1)创建型模式

单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式

2)结构型模式

适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式

3)行为型模式

模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

 

单例模式

核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

单例模式的优点:

由于单例模式只生成一个实例,减少了系统性能开销。

单例模式可以在系统设置全局的访问点,优化共享资源访问。例如可以设计一个单例类,负责所有数据表的映射处理。

常见的五种单例模式的实现方式:

主要:

饿汉式(线程安全,调用效率高。但是,不能延时加载。)

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; } }

 

posted @ 2019-03-07 23:32  涛先森の日常  阅读(322)  评论(0编辑  收藏  举报