单例模式,可以说是GOF的23种设计模式中最简单的一个。
这个模式相对于其他几个模式比较独立,它只负责控制自己的实例化数量单一(而不是考虑为用户产生什么样的实例),很有意思,是一个感觉上很干净的模式,本人很喜欢这个模式。
android中很多地方都用到了单例模式,本文以输入法管理者InputMethodManager为例,展开分析。
单例模式,Singleton Pattern,能够以其特有的优势,替代系统中全局变量,应用非常广泛。
1.意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
热门词汇:单例 唯一 私有构造
2.结构
android中有很多系统级别的全局变量,如时间,输入法,账户,状态栏等等,android中对这些都直接或者有些间接用到了单例模式。
以输入法为例,把上图修改为实际情况:
非常的简单,但是有一点,从上面我们也看到了synchronized关键字,在多线程的环境下,单例模式为了保证自己实例数量的唯一,必然会做并发控制。
类似这种线程安全的单例,跨进程的单例,参数化的单例等等的情况,确实超出本文的范围,而且都涉及到很多东西,是一个很大的话题,不好展开。
3. 代码:
public final class InputMethodManager {
staticfinal Object mInstanceSync =new Object();//同步
//内部全局唯一实例
staticInputMethodManager mInstance;
//对外api
staticpublic InputMethodManager getInstance(Context context) {
returngetInstance(context.getMainLooper());
}
/**
* 内部api,供上面的外部api调用
* @hide 系统隐藏的api
*/
staticpublic InputMethodManager getInstance(Looper mainLooper) {
synchronized(mInstanceSync) {
if(mInstance != null) {
returnmInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
mInstance =new InputMethodManager(service, mainLooper);
}
returnmInstance;
}
}
客户端调用,比如contextimpl中的getSystemService()方法中如下调用:
class ContextImpl extends Context{
@Override
publicObject getSystemService(String name) {
if(WINDOW_SERVICE.equals(name)) {
//... ... 省略下面n个if,else if
}else if(INPUT_METHOD_SERVICE.equals(name)) {
//获取输入法管理者唯一实例
returnInputMethodManager.getInstance(this);
} else if(KEYGUARD_SERVICE.equals(name)) {
//... ... 省略下面n个if,else if
}else if(ACCESSIBILITY_SERVICE.equals(name)) {
//又见单例,无处不在
returnAccessibilityManager.getInstance(this);
}else if(LOCATION_SERVICE.equals(name)) {
//... ... 省略下面n个if,else if
} else if(NFC_SERVICE.equals(name)) {
returngetNfcManager();
}
returnnull;
}
}
非常简单,干净的一个模式。
4.效果
(1).创建型模式。
(2).对唯一实例的受控访问。
(3).避免全局变量污染命名空间。
(4).允许对操作和表示的精化。
(5).比类操作更灵活。
特点
1,该类只有一个实例
2,该类自行创建该实例(在该类内部创建自身的实例对象),就是自己已经new了
3,向整个系统公开这个实例接口
单例模式的俩种方式: 饿汉式 class Singleton { private static Singleton instance=new Singleton(); private Singleton(){} static Singleton getInstance() { return instance; } }
对于资源密集,配置开销较大的单体更合理的做法是将实例化(new)推迟到使用它的时候 懒汉式 class Singleton { private static Singleton instance=null; private Singleton(){}
//公开,静态的工厂方法,需要使用时才去创建该单体 public static Singleton getInstance() { if(instance==null) instance=new Singleton(); return instance; } }
单例模式在JS的应用 参考来自http://www.cnblogs.com/snandy/archive/2011/04/07/2007717.html
单例模式是Javascript最基本,最有用的模式之一。它提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码通过单一的变量进行访问。
单体在Javascipt中有许多用处,可以用来划分命名空间,以减少全局变量的泛滥。还可以用在分支技术中用来处理各浏览器的差异。
Javascript中单例模式的实现方式有多种,每一种都有自身的优点或缺点。
var Singleton = {
attr1 : 1,
attr2 : 'hello',
method1 : function(){alert(this.attr2);},
method2 : function(arg){}
}
这种方式中,对象所有成员都通过Singleton加点号访问。所有成员是公开的,没有私有的。在执行到变量Singleton时,会加载(实例化)自身,即非惰性加载。
此外method1用this访问单体的其它成员会存在一些风险,因为method1的上下文不是总是指向Singleton对象。
比如当把method1作为事件监听器时,this可能指向的是dom元素,这时可能会提示undefined。
var Singleton = function(){
var attr = 1, fn = function(){};
return {
method : function(){ fn(); },
getAttr : function(){ return attr; }
};
}();
这种方式中var定义私有的成员属性attr,方法fn,然后返回一个公开的接口method和getAttr。今后修改实现时,接口方法method和getAttr不变,只需修改私有的attr和fn的具体实现。使用如下
1
2
|
Singleton.method();
Singleton.getAttr();
|
|
适用场合上面已经提到:对于那些必须加载大量数据的单体直到需要使用它的时候才实例化。使用方式是这样的
1
2
|
LazySingleton.getInstance().method();
LazySingleton.getInstance().getAttr();
|
1
2
3
4
5
6
7
|
function
singleton() {
var
obj =
new
Object();
singleton =
function
() {
return
obj;
};
return
obj;
}
|
仅在第一次时会new,这个Object泛指自定义的所有类。