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; } }
作者:涛先森の日常
出处:https://www.cnblogs.com/it-taosir/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。