🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### java中有23种设计模式 #### 单例设计模式 - 概念 类的单态设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 - 解决的问题: 就是可以保证一个类在内存中的对象唯一性。(堆内存中只有一个对象) 比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。 - Runtime()方法就是单例设计模式进行设计的。 - 如何保证对象唯一性呢? - 思想: 1,不让其他程序创建该类对象。 2,在本类中创建一个本类对象。 3,对外提供方法,让其他程序获取这个对象。 - 步骤: 1,因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该类对象; 2,就在类中创建一个本类的对象; 3,定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控) - 代码体现: 1,私有化构造函数; 2,创建私有并静态的本类对象; 3,定义公有并静态的方法,返回该对象。 #### 饿汉式 直接将对象定义出来 - 示例 ~~~ class Single{ //一、私有化构造方法 private Single(){} //二、创建私有并静态的本类对象; private static Single s = new Single();//类已加载,对象就已经存在了 //三、定义公有并静态的方法,返回该对象。 public static Single getInstance(){ return s ; } } class SingleDemo{ public static void main(String[] args){ Single s1 = Single.getInstance(); Single s2 = Single. getInstance(); System.out.println(s1 == s2); } } ~~~ - 输出结果 ~~~ true ~~~ - PS 之所以不用Single.s;的方式获取Single对象,而采用getInstance获取是因为在getInstance方法中我们可以做一些判断来决定是否返回Single的对象,也就是实现了对单例对象的可控。所以,给Single的构造方法加上了private限制,禁止使用者直接采用Single.s;的方式获取。 - 注意:static修饰,随着类的加载而加载,会损耗性能,但方法相对简单,开发时,常用饿汉式,但是面试时,懒汉式的提问较多 #### 懒汉式 - 懒汉式:延迟加载方式。只给出变量,并不将其初始化; - 示例 ~~~ class Single{ //类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象 //延迟加载形式 private static Single s = null; private Single(){} public static Single getInstance(){ if(s == null) s = new Single(); return s ; } } class SingleDemo{ public static void main(String[] args){ Single s1 = Single. getInstance(); Single s2 = Single. getInstance(); System.out.println(s1 == s2); } } ~~~ - 运行结果 ~~~ true ~~~ - 延迟加载方式,类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象;只给出变量,并不将其初始化,第一次用的时候相对较慢,因为需要加载;线程不安全,有可能保证不了对象的唯一性。 - 总结: 饿汉式:static修饰,随着类的加载而加载,会损耗性能,但是方法相对简单 懒汉式 :第一次用的时候相对较慢,因为需要加载!线程,不安全! [Android开发设计模式之——单例模式 ](http://blog.csdn.net/beyond0525/article/details/22794221) 单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问到。比如在Android实际APP 开发中用到的 账号信息对象管理, 数据库对象(SQLiteOpenHelper)等都会用到单例模式。 - 一、作用 单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点 - 二、适用场景 1. 应用中某个实例对象需要频繁的被访问。 2. 应用中每次启动只会存在一个实例。如账号系统,数据库系统。 - 三、常用的使用方式 (1)懒汉式 这是在开发中很容易就能写出来的一种方式,如下 ~~~ public class Singleton { /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */ private static Singleton instance = null; /* 私有构造方法,防止被实例化 */ private Singleton() { } /* 1:懒汉式,静态工程方法,创建实例 */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ~~~ 调用:`Singleton.getInstance().method();` 优点:延迟加载(需要的时候才去加载) 缺点: 线程不安全,在多线程中很容易出现不同步的情况,如在数据库对象进行的频繁读写操作时。 (2)加同步锁 既然线程不安全,那就加上同步锁,一种加法如下: ~~~ /*2.懒汉式变种,解决线程安全问题**/ public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } ~~~ 更一般的写法是这样 ~~~ /*加上synchronized,但是每次调用实例时都会加载**/ public static Singleton getInstance() { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } return instance; } ~~~ 调用:`Singleton.getInstance().method(); ` 优点:解决了线程不安全的问题。 缺点:效率有点低,每次调用实例都要判断同步锁 补充:在android源码中使用的该单例方法有:InputMethodManager,AccessibilityManager等都是使用这种单例模式 (3)双重检验锁 要优化(2)中因为每次调用实例都要判断同步锁的问题,很多人都使用下面的一种双重判断校验的办法 ~~~ /*3.双重锁定:只在第一次初始化的时候加上同步锁*/ public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } ~~~ 这种方法貌似很完美的解决了上述效率的问题,它或许在并发量不多,安全性不太高的情况能完美运行,但是,这种方法也有不幸的地方。问题就是出现在这句`instance = new Singleton(); ` 在JVM编译的过程中会出现指令重排的优化过程,这就会导致当 instance实际上还没初始化,就可能被分配了内存空间,也就是说会出现 instance !=null 但是又没初始化的情况,这样就会导致返回的 instance 不完整(可以参考:http://www.360doc.com/content/11/0810/12/1542811_139352888.shtml)。 调用:`Singleton.getInstance().method();` 优点:在并发量不多,安全性不高的情况下或许能很完美运行单例模式 缺点:不同平台编译过程中可能会存在严重安全隐患。 补充:在android图像开源项目Android-Universal-Image-Loader (https://github.com/nostra13/Android-Universal-Image-Loader) 中使用的是这种方式。 (4)内部类的实现 内部类是一种好的实现方式,可以推荐使用一下: ~~~ public class SingletonInner { /** * 内部类实现单例模式 * 延迟加载,减少内存开销 * * @author xuzhaohu * */ private static class SingletonHolder { private static SingletonInner instance = new SingletonInner(); } /** * 私有的构造函数 */ private SingletonInner() { } public static SingletonInner getInstance() { return SingletonHolder.instance; } protected void method() { System.out.println("SingletonInner"); } } ~~~ 调用:`SingletonInner.getInstance().method();` 优点:延迟加载,线程安全(java中class加载时互斥的),也减少了内存消耗 (5)枚举的方法 这是网上很多人推荐的一种做法,但是貌似使用的不广泛,大家可以试试, ~~~ /** * @function:单例模式枚举实现 * @author xuzhaohu * */ public enum SingletonEnum { /** * 1.从Java1.5开始支持; * 2.无偿提供序列化机制; * 3.绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候; */ instance; private String others; SingletonEnum() { } public void method() { System.out.println("SingletonEnum"); } public String getOthers() { return others; } public void setOthers(String others) { this.others = others; } } ~~~ 调用:`SingletonEnum.instance.method();` 优缺点:如代码中注释。 上面主要讲了单例模式5种创建方法,大家可以根据其优缺点进行个人实际项目中的使用。讲的属于抛砖引玉,大家多提意见。 参考:http://zz563143188.iteye.com/blog/1847029