设计模式篇|单例模式

2019-08-12  本文已影响0人  青年心路

一、简介

1.什么是设计模式

设计模式是一套被 反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。

2.为什么要使用设计模式

为了可重用代码,让代码更容易的被他人理解并保证代码的可靠性。

二、GOF23

创建型模式:

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

结构性模式:

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

行为型模式

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

三、单例模式概念及其实现

核心作用:

常见应用场景
1.Windows的Task Manager(任务管理器)就是很经典的单例模式
2.Windows的Recycle Bin(回收站)也是典型的单例模式应用,在整个系统运行中,回收站一直维护者仅有的一个实例
3.网站的计数器,一般也采用单例模式,否则难以同步
4.数据库的连接池设计一般也采用单例模式,因为数据库连接是一种数据库资源
5.在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理

单例模式的优点

1.由于单例模式只生成一个实例,减少了系统性能开销。
2.单例模式可以在系统设置全局访问点,优化环共享资源访问。

单例模式的五种实现方式
主要
其他
/**
 * 饿汉式单例模式
 */
public class SingletonDemo01 {

    //1.将实例设置为静态、私有的
    //类初始化时立即加载
    private static SingletonDemo01 instance = new SingletonDemo01();

    //2.将构造器私有
    private SingletonDemo01(){
    }

    //3.提供访问点
    public static SingletonDemo01 getInstance(){
        return instance;
    }
}

在公有方法处不需要添加synchronized,因为静态对象在类加载时进行初始化,此时天然线程安全,但是没有延时加载,如果最终资源没有被使用,会造成资源的浪费。因为没有加同步,所以执行效率高。

/**
 * 懒汉式单例模式
 */
public class SingletonDemo02 {

    private static SingletonDemo02 instance;

    private SingletonDemo02(){

    }

    public static synchronized SingletonDemo02 getInstance(){
        if (instance == null){
            instance = new SingletonDemo02();
        }
        return instance;
    }
}

懒汉式在公有方法处需要加synchronized关键字,因为不添加同步的话,在多线程情况下有可能会对单例模式造成破坏。懒汉式加载可以避免资源的浪费,但是因为加了同步,所以调用效率比较低。

/**
 * 双重检测锁式
 */
public class SingletonDemo03 {

    private static SingletonDemo03 instance = null;

    private SingletonDemo03(){}

    public static SingletonDemo03 getInstance(){
        if (instance == null){
            SingletonDemo03 sc;
            synchronized (SingletonDemo03.class){
                sc = instance;
                if (sc == null){
                    synchronized (SingletonDemo03.class){
                        if (sc == null){
                            sc = new SingletonDemo03();
                        }
                    }
                    instance = sc;
                }
            }
        }
        return instance;
    }
}

优点:

缺点:

public class SingletonDemo04 {

    private SingletonDemo04(){}

    private static class SingletonClassInstance{
        private static final SingletonDemo04 instance = new SingletonDemo04();
    }

    public static SingletonDemo04 getInstance(){
        return SingletonClassInstance.instance;
    }
}

要求:

public enum  SingletonDemo05 {

    /**
     * 定义一个枚举元素,他就代表了Singleton的一个实例
     */
    INSTANCE;
}

优点:

缺点:

如何选用
关于单例模式的破解

注意:枚举方式由于JVM底层的原因,所以无法破解
方式一:通过反射

        //通过反射方式直接调用私有构造器
        Class<SingletonDemo01> clazz = (Class<SingletonDemo01>) Class.forName("com.hxx.singleton.SingletonDemo01");
        //获取构造器
        Constructor<SingletonDemo01> constructor = clazz.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        //通过构造器创建实例
        SingletonDemo01 s3 = constructor.newInstance();
        SingletonDemo01 s4 = constructor.newInstance();

        System.out.println(s3 == s4);

方式二:通过反序列化

        //通过反序列化方式调用
        FileOutputStream fos = new FileOutputStream("D:/a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(s1);

        oos.close();
        fos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/a.txt"));
        SingletonDemo01 s3 = (SingletonDemo01) ois.readObject();
        System.out.println(s3);
解决破解

破解反射

    //2.将构造器私有
    private SingletonDemo01(){
        if (instance != null){
            throw new RuntimeException();
        }
    }

在构造器中对instance进行判断

破解反序列化

`  private Object readResolve(){
        return instance;
    }

在单例模式的方法中添加readResolve方法。

上一篇 下一篇

猜你喜欢

热点阅读