Android中单例模式

来源:互联网 发布:怎么把mac照片导入u盘 编辑:程序博客网 时间:2024/06/11 13:47

设计模式系列:
        0. Android开发常用设计模式;

        1. Android中单例模式;

        2. Android中建造者(builder)模式;

        3. Android中观察者模式;

        4. Android中原型模式;

        5. Android中策略模式;

        6. Android中工厂模式;

        7. Android中代理模式;

        8. Android中装饰者模式;

        9. Android中适配器模式;


单利模式定义:核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。

一、常见需求场景


  三毛:“小白,你对后台返回来的json数据解析是用json还是Gson吖”

  小白:我是用的Gson解析后台返回来的数据,怎么了?


二、基本解决方法


  三毛:“那你是怎样使用Gson的呢”

  小白:因为我一般都是拿到后台给的json字符串数据,然后转换成实体类对象,就像下面拿到json字符串jsonStr,然后转换成实体类A

 //初生牛犊不怕虎的(普通写法) Gson gson = new Gson(); A aBean = gson.fromJson(jsonStr, A.class);


三、基本解决方法存在的问题


  三毛:“我的白,你这样new,new,new,一两个没啥问题,但是几十个,几百个,会存在内存占用多和不同对象对同一个资源的操作的问题波”

  小白:毛毛哥说得是,确实是这样,那我给Gson写一个类,然后调用它来解析,像下面那样

//饿汉式单例写法public class GsonSingle {    private static Gson mGson = new Gson();    private GsonSingle() {//构造函数设置为private,防止外部程序通过new来构造    }    public static Gson getInstance() {        return mGson;    }}//调用gson单利类来解析 A aBean = GsonSingle.getInstance().fromJson(jsonStr, A.class);

  三毛:”白啊,你这样确实解决了一直new,new,new的问题,假设你这个GsonSingle类不使用getInstance静态方法的时候,而是使用其他静态方法,那你静new出来的静态实例不就浪费内存资源了嘛”

  小白:啪啪啪(敲键盘这里写图片描述),我改成下面那样子,毛毛哥看看这下Ok了吧

//懒汉式写法public class GsonSingle {    private static Gson mGson = null;    private GsonSingle() {    }    public static Gson getInstance() {        if (mGson == null) {            mGson = new Gson();        }        return mGson;    }}

  三毛:“你这样写,正常来看是没什么问题,但是在多线程的情况下就会出现另外的问题,多线程并发,线程不安全的情况呢”;

  小白:那我给它加个锁synchronized,变成下面那样子,怎么样,这下没什么好说的了吧;

//懒汉式枷锁写法public class GsonSingle {    private static Gson mGson = null;    public static synchronized Gson getInstance() {        if (mGson == null) {            mGson = new Gson();        }        return mGson;    }}

  三毛:“嘿嘿,这样加锁确实处理了多线程并发的问题,但是当你次次获取单例都同步,那不和前面一样,造成资源浪费了吗,也就是说等于没啥子改进的啵”

  小白:有点道理,啪啪啪(敲键盘),好了,调下位置,改成下面那样,这样一来就不会次次都因为同步造成资源浪费了吧

//懒汉式双重枷锁写法public class GsonSingle {    private static Gson mGson = null;    private GsonSingle() {    }    public static Gson getInstance() {        //先检查实例是否存在,如果不存在才进入下面的同步块        if(mGson == null){            //同步块,线程安全地创建实例            synchronized(Gson.class){                //再次检查实例是否存在,如果不存在才真正地创建实例                if(mGson == null){                    mGson = new Gson();                }            }        }        return mGson;    }}

  三毛:“嗯,是的,不过你这样写第一次加载类的时候还是需要同步,也就意味着第一次加载类会牺牲一点时间,你觉得还能改进嘛”

  小白:我想不到其他改进的办法了

  三毛:“嘿嘿嘿,可能你一时忘记了,其实可以用内部类来写单例,像下面这样”

//内部类单例写法public class GsonSingle {    private GsonSingle() {    }    public static Gson getInstance() {        return GsonSingleHolder.gson;    }    private static class GsonSingleHolder {        private static final Gson gson = new Gson();    }}

  小白:握草,居然还有这种操作,三毛哥,你平常的单例都是用这中内部类的方式吗?

  三毛:“大部分都是用的内部类写单例,也有时候偷懒,像你第一种方式直接在类里new一个静态对象,不过我还是看情况来选择,另外你上面的改进也是属于单例设计模式中的几种写法,其实还有网络江湖上流传的另外2中写法你可能没想到,那就是枚举单例和容器单例”

  小白:嗷嗷嗷,和毛毛哥聊天又学到东西了,我看看枚举单例和容器单例去~~


四、单例模式和普通写法的区别


  1.一个类只有一个实例
  2.自己创建这个实例
  3.整个系统只能用这个实例
  4.内存开销减少了,降低多个对象访问同一个资源造成并发问题情况

原创粉丝点击