软件设计原则有哪些(下)

简介: 软件设计原则有哪些(下)

存在的问题

问题演示

破坏单例模式:

使上面定义的单例类(Singleton)可以创建多个对象,枚举方式除外。有两种方式,分别是序列化和反射。

序列化反序列化
public class Singleton implements Serializable {
    //私有构造方法
    private Singleton() {}
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        //往文件中写对象
        //writeObject2File();
        //从文件中读取对象
        Singleton s1 = readObjectFromFile();
        Singleton s2 = readObjectFromFile();
        //判断两个反序列化后的对象是否是同一个对象
        System.out.println(s1 == s2);
    }
    private static Singleton readObjectFromFile() throws Exception {
        //创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\Users\Think\Desktop\a.txt"));
        //第一个读取Singleton对象
        Singleton instance = (Singleton) ois.readObject();
        return instance;
    }
    public static void writeObject2File() throws Exception {
        //获取Singleton类的对象
        Singleton instance = Singleton.getInstance();
        //创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\Users\Think\Desktop\a.txt"));
        //将instance对象写出到文件中
        oos.writeObject(instance);
    }
}

上面代码运行结果是false,表明序列化和反序列化已经破坏了单例设计模式。

反射
public class Singleton {
    //私有构造方法
    private Singleton() {}
    private static volatile Singleton instance;
    //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        if(instance != null) {
            return instance;
        }
        synchronized (Singleton.class) {
            if(instance != null) {
                return instance;
            }
            instance = new Singleton();
            return instance;
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        //获取Singleton类的字节码对象
        Class clazz = Singleton.class;
        //获取Singleton类的私有无参构造方法对象
        Constructor constructor = clazz.getDeclaredConstructor();
        //取消访问检查
        constructor.setAccessible(true);
        //创建Singleton类的对象s1
        Singleton s1 = (Singleton) constructor.newInstance();
        //创建Singleton类的对象s2
        Singleton s2 = (Singleton) constructor.newInstance();
        //判断通过反射创建的两个Singleton对象是否是同一个对象
        System.out.println(s1 == s2);
    }
}

上面代码运行结果是false,表明序列化和反序列化已经破坏了单例设计模式

注意:枚举方式不会出现这两个问题。

问题的解决

序列化、反序列方式破坏单例模式的解决方法

在Singleton类中添加readResolve()方法,在反序列化时被反射调用,如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新new出来的对象。

public class Singleton implements Serializable {
    //私有构造方法
    private Singleton() {}
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    /**
     * 下面是为了解决序列化反序列化破解单例模式
     */
    private Object readResolve() {
        return SingletonHolder.INSTANCE;
    }
}
反射方式破解单例的解决方法
public class Singleton {
    //私有构造方法
    private Singleton() {
        /*
           反射破解单例模式需要添加的代码
        */
        if(instance != null) {
            throw new RuntimeException();
        }
    }
    private static volatile Singleton instance;
    //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        if(instance != null) {
            return instance;
        }
        synchronized (Singleton.class) {
            if(instance != null) {
                return instance;
            }
            instance = new Singleton();
            return instance;
        }
    }
}

这种方式比较好理解。当通过反射方式调用构造方法进行创建创建时,直接抛异常。不运行此中操作。



目录
相关文章
|
3月前
软件设计原则:耦合与内聚
软件设计原则:耦合与内聚
56 0
|
5月前
|
存储 安全 算法
系统设计的端到端原则
系统设计的端到端原则
31 0
|
9月前
|
设计模式 算法
软件设计的原则
软件设计的原则
50 0
|
9月前
|
数据库
软件设计原则
软件设计原则
|
9月前
|
设计模式 算法
原则的重要性(单一职责原则-开放封闭原则)一
原则的重要性(单一职责原则-开放封闭原则)一
65 0
|
10月前
|
设计模式 安全 Java
软件设计原则有哪些(上)
软件设计原则有哪些(上)
86 0
|
11月前
|
程序员 测试技术
面向对象设计五个基本原则
只有聪明人才能看见的简介~( ̄▽ ̄~)~
78 0
|
12月前
|
消息中间件 架构师 Java
软件架构的23个基本原则
软件架构的23个基本原则
|
消息中间件 存储 架构师
软件架构的 23 个基本原则
软件架构的 23 个基本原则
244 0
软件架构的 23 个基本原则
软件架构设计原则--迪米特原则
本专栏内容参考自:咕泡学院Tom老师的《Spring5核心原理与30个类手写实战》,仅作个人学习记录使用,如有侵权,联系速删
软件架构设计原则--迪米特原则