zoukankan      html  css  js  c++  java
  • 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; } }
  • 相关阅读:
    创建一个 mac 的后台进程(daemon)
    Centos 7创建一个服务
    MAC配置VIM环境
    Spark源码剖析(九):TaskScheduler原理与源码剖析
    Spark源码剖析(八):stage划分原理与源码剖析
    教你如何写递归(数学归纳法,干货强推!)
    Spark源码剖析(七):Job触发流程原理与源码剖析
    剑指offer:变态跳台阶
    Spark源码剖析(六):Worker原理与源码剖析
    Spark源码剖析(五):Master原理与源码剖析(下)
  • 原文地址:https://www.cnblogs.com/it-taosir/p/10017549.html
Copyright © 2011-2022 走看看