当前位置: 首页 > 科技观察

Android设计模式之单例模式

时间:2023-03-22 14:00:41 科技观察

经常有人问我如何推进Android学习?不管怎么走,设计模式都是进阶必备的。设计模式的理解和运用,对你后续的代码编写和架构设计都有很大的帮助,所以我从今天的模式系列开始抽空和大家分享设计。什么是设计模式?其实简单的理解只是对前人留下的一些经验的总结,然后这些经验就叫做DesignPattern,翻译过来就是设计模式的意思。通过使用设计模式,我们的代码可以更加可重用。它更易于维护,并使您的代码更优雅。理论上有23种设计模式,但我只分享一些Android平台上常用的设计模式。今天先分享最常用的单例模式。饿了么风格publicclassSingleton{privatestaticSingletoninstance=newSingleton();privateSingleton(){}publicstaticSingletonnewInstance(){返回实例;在这种情况下,这种方法简单粗暴。如果单例对象的初始化速度非常快,内存占用又非常小,这种方法比较合适。它可以在应用程序启动时直接加载和初始化。但是,如果单例初始化操作耗时较长,应用对启动速度有要求,或者单例占用内存较大,或者单例只在特定场景下使用,一般情况下不用的时候,用饿了么的单例模式是不合适的。这时候就需要使用懒人的方式,按需延迟加载单例了。惰性风格publicclassSingleton{privatestaticSingletoninstance=null;privateSingleton(){}publicstaticnewInstance(){if(null==instance){instance=newSingleton();}返回实例;实例的初始化操作被延迟到需要的时候,这在某些场合非常有用。比如一个单例,使用次数不多,但是这个单例提供的功能非常复杂,加载和初始化会消耗大量资源。这时候使用懒人风格是一个非常好的选择。多线程下的单例模式上面介绍了单例模式的一些基本应用方法,但是上面说的这些使用方法都有一个隐含的前提,就是都是在单线程条件下应用的。如果变成多线程,就有出错的风险。在多线程的情况下,hungry风格不会有问题,因为JVM只会加载一次单例类,但是lazy风格可能会出现重复创建单例对象的问题。为什么会出现这样的问题?因为lazy风格在创建单例的时候不是线程安全的,可能会有多个线程并发调用他的newInstance方法,导致多个线程创建同一个单例的多个副本。有没有办法让懒人的单利模型也线程安全?答案是肯定的,就是通过加同步锁来实现。惰性同步锁publicclassSingleton{privatestaticSingletoninstance=null;privateSingleton(){}publicstaticSingletongetInstance(){synchronized(Singleton.class){if(instance==null){instance=newSingleton();}}返回实例;解决同步问题的常用方法是使用一个同步锁synchronized(Singleton.class)来防止多个线程同时进入导致实例被多次实例化。举一个在Android中使用该方法的例子:InputMethodManagerexamplepublicfinalclassInputMethodManager{//内部全局唯一实例staticInputMethodManagersInstance;//外部apipublicstaticInputMethodManagergetInstance(){synchronized(InputMethodManager.class){if(sInstance==null){IBinderb=ServiceManager.getService(Context.INPUT_METHOD_SERVICE);IInputMethodManagerservice=IInputMethodManager.Stub.asInterface(b);sInstance=newInputMethodManager(服务,Looper.getMainLooper());}返回实例;方式。但是其实还有一个更好的方法如下:doublechecklockpublicclassSingleton{privatestaticvolatileSingletoninstance=null;privateSingleton(){}publicstaticSingletongetInstance(){//ifalreadyinited,noneedtogetlockeverytimeif(instance==null){synchronized(Singleton.class){if(instance==null){instance=newSingleton();}}}返回实例;可以看到在上面的synchronized(Singleton.class)外加了一层if,就是在实例已经实例化后下载第一个入口,不需要执行synchronized(Singleton.class)获取对象锁,从而提高性能。以上两种方法都比较麻烦。我们不禁要问,有没有更好的实现方式呢?答案是肯定的。我们可以利用JVM的类加载机制来实现。在很多情况下,JVM已经为我们提供了同步控制,比如:当static{}块中初始化的数据访问final字段时等。因为它会保证JVM进行类加载时数据是同步的,所以我们可以这样实现:使用一个内部类,在这个内部类中创建一个对象实例。这样,只要应用程序不使用内部类,JVM就不会加载单例类,也不会创建单例对象,从而实现了延迟加载和线程安全。实现代码如下:staticinnerclasspublicclassSingleton{//内部类,加载内部类时会创建单兴趣对象privatestaticclassSingletonHolder{publicstaticSingletoninstance=newSingleton();}privateSingleton(){}publicstaticSingletonnewInstance(){returnSingletonHolder.instance;}publicvoiddoSomething(){//dosomething}}这样实现的单例类是线程安全的,使用起来非常简单。妈妈再也不用担心我的单身狗不是单身狗了。但是,这不是最简单的方法。EffectiveJava推荐一种更简洁方便的使用方式,那就是使用枚举。枚举类型单例模式publicenumSingleton{//定义一个枚举元素,它是Singleton的实例实例;publicvoiddoSomething(){//dosomething...}}使用方法如下:publicstaticvoidmain(String[]args){Singletonsingleton=Singleton.instance;singleton.doSomething();}默认枚举实例的创建是线程安全的。(创建枚举类的单例也可以在JVM层面保证线程安全),所以不用担心线程安全问题,所以理论上枚举类实现单例模式是最简单的方法。总结一下,一般的单例模式包括5种写法,分别是饿汉、懒汉、双重检查锁、静态内部类和枚举。相信看完之后你对单例模式有了一个全面的了解,根据不同的场景选择自己喜欢的单例模式吧!

最新推荐
猜你喜欢