设计模式单例模式

1.单利模式的定义及使用场景
确保某一个类只有一个实例,而且自行示例化并向整个系统提供这个实例。确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象应该有且只有一个。例如创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单例模式。

《设计模式单例模式》 Paste_Image.png

2.单例模式的优缺点

2.1优点

减少内存,特别是一个对象需要频繁地创建、销毁,而且创建或销毁时性能又无法优化

单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免同时对一个资源文件的同时写操作

单例模式可以在系统设置全局的访问点,优化和共享资源访问

2.2缺点

单例模式一般没有接口,扩展比较困难
单例模式与单一责任原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中3.单例模式的实现方式
3.1懒汉模式

最原始的懒汉模式
优点:懒加载
缺点:未考虑线程安全

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}```
加锁的懒汉模式
优点:懒加载 、线程安全

缺点:效率低

public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}“`
双重锁懒汉模式
优点:懒加载、线程安全

缺点:效率高于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;  
     }  
 }```
静态内部类
优点:懒加载、线程安全

缺点:实现方式比较复杂

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数组中,以这种方式进行单例的提供。
出处:http://huangjunbin.com/page/4/
    原文作者:GB_speak
    原文地址: https://www.jianshu.com/p/8035edbb3958
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞