保证一个类仅有一个实例,并提供一个访问它的全局访问点。
适用性
1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
2.当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
参与者
Singleton
定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作。
可能负责创建它自己的唯一实例。
类图
例子
Singleton
public class Singleton {
private static Singleton sing;
private Singleton() {
}
public static Singleton getInstance() {
if (sing == null) {
sing = new Singleton();
}
return sing;
}
}
Test
public class Test {
public static void main(String[] args) {
Singleton sing = Singleton.getInstance();
Singleton sing2 = Singleton.getInstance();
System.out.println(sing);
System.out.println(sing2);
}
}
result
singleton.Singleton@1c78e57
singleton.Singleton@1c78e57
SDK源码例子
android中有很多系统级别的全局变量,如时间,输入法,账户,状态栏等等,android中对这些都直接或者有些间接用到了单例模式。
public final class InputMethodManager {
static final Object mInstanceSync = new Object();//同步
//内部全局唯一实例
static InputMethodManager mInstance;
//对外api
static public InputMethodManager getInstance(Context context) {
return getInstance(context.getMainLooper());
}
/**
* 内部api,供上面的外部api调用
* @hide 系统隐藏的api
*/
static public InputMethodManager getInstance(Looper mainLooper){
synchronized (mInstanceSync) {
if (mInstance != null) {
return mInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
mInstance = new InputMethodManager(service, mainLooper);
}
return mInstance;
}
}
客户端调用,比如contextimpl中的getSystemService()方法中如下调用:
class ContextImpl extends Context{
@Override
public Object getSystemService(String name) {
if (WINDOW_SERVICE.equals(name)) {
//... ... 省略下面n个if,else if
} else if (INPUT_METHOD_SERVICE.equals(name)) {
//获取输入法管理者唯一实例
return InputMethodManager.getInstance(this);
} else if (KEYGUARD_SERVICE.equals(name)) {
//... ... 省略下面n个if,else if
} else if (ACCESSIBILITY_SERVICE.equals(name)) {
//又见单例,无处不在
return AccessibilityManager.getInstance(this);
} else if (LOCATION_SERVICE.equals(name)) {
//... ... 省略下面n个if,else if
} else if (NFC_SERVICE.equals(name)) {
return getNfcManager();
}
return null;
}
}
效果
(1).创建型模式。
(2).对唯一实例的受控访问。
(3).避免全局变量污染命名空间。
(4).允许对操作和表示的精化。
(5).比类操作更灵活。