### 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