设计模式-单例模式

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数组中,以这种方式进行单例的提供。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值