再战设计模式(一)之单例模式
关于设计模式,之前已经看过很多很多了.但是每次到过了很久之后,在此回忆总是感觉有模糊的感觉.这次我要重新学习一下设计模式.并在这里做一个博客记录,以作为以后的备忘吧.大家看过如果有问题或者更好的方式,可以在评论留言
这篇文章也是我写设计模式的开章.主要方式是看视频和看书,设计模式被人称为GOF23 主要就是国外有4个编程牛人编写的这23中设计模式.大家主要理解人家的思想.而不是死记硬背,这句话也是对我自己说的.
设计模式的分类
1.创建型模式:5种
单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式
2.结构型模式 7种
适配模式 桥接模式 装饰模式 组合模式 外观模式 享元模式 代理模式
3.行为模式:11 种
模板方法模式 命令模式 迭代器模式 观察者模式 中介者模式 备忘录模式 解释器模式 状态模式 策略模式 职责链模式 访问者模式
分类主要是为了方便记忆 突然想到了jdk 8 有 9个函数式接口 想回忆下
单例模式的实现
单例模式-饿汗模式
饿汉模式顾名思义就是非常饿,直接吃.其实关于单例模式的总结就一句话,私有构造方法,提供外部获取实例的方法
所以在类加载的时候对象已经创建好了.方法没有锁,调用效率高!
/** * @Created by xiaodao */ public class Sington01 { //类初始化时立即加载对象(没有延迟加载的优势),天然的线程安全 private static Sington01 instance = new Sington01(); private Sington01() { } public static Sington01 getInstance(){ return instance; } }
延时加载模式
public class Sington02 { /*** * 延时加载模式,在调用的时候,才会获取对像 */ private static Sington02 sington ; private Sington02() { } /** * 同步调用效率低 * @return */ public static Sington02 getInstance(){ synchronized (Sington02.class){ if(null == sington){ sington= new Sington02(); } return sington; } } }
双重检查 double-check单例模式
/** * @Created by xiaodao * 双重检索模式 */ public class Sington03 { /*** * */ private static volatile Sington03 sington ; private Sington03() { } /** * * @return */ public static Sington03 getInstance(){ if(sington !=null ){ }else{ synchronized (Sington03.class){ if(sington== null){ sington = new Sington03(); } } } return sington; } public static void main(String[] args) { Sington03 sington03 = getInstance(); Sington03 sington04 = getInstance(); System.out.println(sington03); System.out.println(sington04); } }
静态内部类 延时加载模式
/** * @Created by xiaodao * */ public class Sington04 { /*** * */ private static class Sington04Interior { private static Sington04 instance= new Sington04(); }; private Sington04() { } /** * * @return */ public static Sington04 getInstance(){ return Sington04Interior.instance; } public static void main(String[] args) { Sington04 sington03 = getInstance(); Sington04 sington04 = getInstance(); System.out.println(sington03); System.out.println(sington04); } }
加载类的时候外部没有static属性不会像恶汉模式一样立即加载对象
只有getInstance才会加载静态内部类.是线程安全的
兼备了并发高效和延迟加载的优势
枚举方式实现单例模式
/** * @Created by xiaodao * */ public enum Sington05 { /*** * 定义一个枚举.代表singleton的一个实例 */ INSTANCE; public void singletonOperator(){ //这个单例的功能处理 } public static void main(String[] args) { Sington05 sington05 = Sington05.INSTANCE; } }
枚举的单例,可以避免反射和反序列来破解,实现比较简单
反射跳过单例
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //第一次调用. // Sington06 instance = Sington06.getInstance(); // System.out.println(instance); Class<Sington06> aClass = (Class<Sington06>) Class.forName("com.xiaodao.jdk8.disign.sington.Sington06"); //获取构造器 //第二次调用. Constructor<Sington06> declaredConstructor = aClass.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); Sington06 s2 = declaredConstructor.newInstance(); Sington06 s1 = declaredConstructor.newInstance(); System.out.println(s1); System.out.println(s2); //第三次. Sington06 instance = Sington06.getInstance(); System.out.println(instance); Sington06 s3 = declaredConstructor.newInstance(); }
这种方式可以跳过单例模式,需要在单例模式里加一个判断.
private Sington06() {
if(sington !=null){
throw new RuntimeException();
}
}
平时我们写项目不需要这样的判断.但是如果是写个框架的话,可能需要严谨一点,但是这也是有漏洞的,如果你没有创建过一次单例,那么通过反射就是无数次调用,如果你创建了.那么就不能通过反射就创建了.
反序列化破解与防止反序列破解
Sington06 instance = Sington06.getInstance(); System.out.println(instance); FileOutputStream out = new FileOutputStream("/Users/xuyuanfang/study/java视频/disgin/a.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(out); objectOutputStream.writeObject(instance); out.close(); objectOutputStream.close(); //反序列化 ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/xuyuanfang/study/java视频/disgin/a.txt")); Sington06 s3 = (Sington06) objectInputStream.readObject(); System.out.println(s3); 防止破解: /** * 反序列化 如果定义了readResolve方法 直接调用这个方法返回对象,不需要重新创建对象 * @return */ public Object readResolve() throws ObjectStreamException { return sington; }
效率对比
恶汉模式,比懒汉方式在多线程环境下效率好点
如何选用呢?
如果对象占用资源少,不需要延时加载
枚举比恶汉式比较好
如果对象资源占用比较大的话.需要延时加载
静态内部类好于懒汉式
一起交流进步.扫描下方QQ二维码即可