1.单利模式的定义及使用场景
确保某一个类只有一个实例,而且自行示例化并向整个系统提供这个实例。确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象应该有且只有一个。例如创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单例模式。
2.单例模式的优缺点
2.1优点
1)减少内存![]()
,特别是一个对象需要频繁地创建、销毁,而且创建或销毁时性能又无法优化
2)单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免同时对一个资源文件的同时写操作
3)单例模式可以在系统设置全局的访问点,优化和共享资源访问
2.2缺点
1)单例模式一般没有接口,扩展比较困难
2)单例模式与单一责任原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中
3.单例模式的实现方式
3.1懒汉模式
1)最原始的懒汉模式
优点:懒加载
缺点:未考虑线程安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2)加锁的懒汉模式
优点:懒加载 、线程安全
缺点:效率低
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3)双重锁懒汉模式
优点:懒加载、线程安全
缺点:效率高于2)
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
4)静态内部类
优点:懒加载、线程安全
缺点:实现方式比较复杂
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
3.2饿汉模式
优点:非懒加载
缺点:线程安全
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
4.单例模式在Android中的实际应用
相信大家对LayoutInflate都不陌生,特别在ListView的Adapter的getView方法中基本都会出现,使用inflate方法去加载一个布局,用于ListView的每个Item的布局。最简单的使用方法是LayoutInflater layoutInflater = LayoutInflater.from(context); 那么Android的源码中是怎么保持LayoutInflater的单例模式呢?分析源码如下:
/**
* Obtains the LayoutInflater from the given context.
*/
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
Context:
@SuppressWarnings("unchecked")
public final <T> T getSystemService(Class<T> serviceClass) {
// Because subclasses may override getSystemService(String) we cannot
// perform a lookup by class alone. We must first map the class to its
// service name then invoke the stringbased method.
String serviceName = getSystemServiceName(serviceClass);
return serviceName != null ? (T)getSystemService(serviceName) : null;
}
public abstract String getSystemServiceName(Class<?> serviceClass);
ContextImpl:
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
SystemServiceRegistry:
/**
* Gets the name of the systemlevel service that is represented by the specified class.
*/
public static String getSystemServiceName(Class<?> serviceClass) {
return SYSTEM_SERVICE_NAMES.get(serviceClass);
}
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
/**
* Statically registers a system service with the context.
* This method must be called during static initialization only.
*/
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
private final int mCacheIndex;
public CachedServiceFetcher() {
mCacheIndex = sServiceCacheSize++;
}
@Override
@SuppressWarnings("unchecked")
public final T getService(ContextImpl ctx) {
final Object[] cache = ctx.mServiceCache;
synchronized (cache) {
// Fetch or create the service.
Object service = cache[mCacheIndex];
if (service == null) {
service = createService(ctx);
cache[mCacheIndex] = service;
}
return (T)service;
}
}
public abstract T createService(ContextImpl ctx);
}
通过源码分析可知,
LayoutInflater最终是保存在cache的一个Object数组中,以这种方式进行单例的提供。