适用的场景在于:对于定义的一个类,在整个应用程序执行期间只有唯一的一个实例对象。通过单例模式,自行实例化并向这个系统提供这个单一实例的访问方法。如Android中常见的Application对象。
根据此单一实例产生的时机不同,可以将其分为懒汉式、饿汉式和登记式。
一、懒汉式:其特点是延迟加载,即当需要用到此单一实例的时候,才去初始化此单一实例。
常见经典的写法如下:
1 package com.qqyumidi;
2
3 public class SingleTon {
5 // 静态实例变量
6 private static SingleTon instance;
8 // 私有化构造函数
9 private SingleTon() {
11 }
13 // 静态public方法,向整个应用提供单例获取方式
14 public static SingleTon getInstance() {
15 if (instance == null) {
16 instance = new SingleTon();
17 }
18 return instance;
19 }
21 }
线程安全的懒汉式单例类的实现:只有一个线程进入该代码块.此时,线程获得的是成员锁
二、饿汉式:特点是还未用到就先实例化。(一定是安全的,只有一份对象)
1.构造器私有化
2.声明私有的静态属性,同时创建该对象
3.对外提供访问属性的静态方法,确保该对象存在。
常见的经典写法为:
1 package com.qqyumidi; 2 3 public class SingleTon { 8 // 私有化构造函数 9 private SingleTon() { 11 } 12 // 静态实例变量,直接初始化
6 private static SingleTon instance = new SingleTon();
13 // 静态public方法,向整个应用提供单例获取方式14 public static SingleTon getInstance() {15 return instance;16 }18 }
三、登记式:
登记式单例模式,一般是通过一个专门的类对各单例模式的此单一实例进行管理和维护。通过Map方式可以方便的实现此目的。
常见的代码如下:
1 package com.qqyumidi;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 public class SingleTonManager {
7
8 private static Map singleTonMap = new HashMap();
9
10 public static void main(String[] args) {
11 // 获取A类的单例
12 A a = (A) getInstance(A.class.getName());
13 // 获取B类的单例
14 B b = (B) getInstance(B.class.getName());
15 }
16
17 // 根据类型获取单例
18 public static Object getInstance(String className) {
19 // 判断singleTonMap中是否有此单例,有则取得后返回,无则添加单例后返回
20 if (!singleTonMap.containsKey(className)) {
21 try {
22 singleTonMap.put(className, Class.forName(className).newInstance());
23 } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
25 e.printStackTrace();
26 }
27 }
28 return singleTonMap.get(className);
29 }
30 }
31
32 class A {
34 }
35
36 class B {
38 }
另外:需要注意的是,在多线程环境中,以上各种方法构造单例模式需要考虑到线程安全问题。
四、改进型懒汉式(直接满足线程安全)——通过静态内部类实现
在如上的懒汉单例模式中,对于多线程环境中。可以通过常见的如synchronized等方式实现线程安全,同时可以通过Java静态内部类的方式实现进一步改进。
常见代码如下:
1 package com.qqyumidi;
2
3 public class SingleTon {
4
5 // 利用静态内部类特性实现外部类的单例
6 private static class SingleTonBuilder {
7 private static SingleTon singleTon = new SingleTon();
8 }
9
10 // 私有化构造函数
11 private SingleTon() {
13 }
14
15 public static SingleTon getInstance() {
16 return SingleTonBuilder.singleTon;
17 }
18
19 public static void main(String[] args) {
20 SingleTon instance = getInstance();
21 }
22 }
其主要原理为:Java中静态内部类可以访问其外部类的成员属性和方法,同时,静态内部类只有当被调用的时候才开始首次被加载,利用此特性,可以实现懒汉式,在静态内部类中静态初始化外部类的单一实例即可。
3.适配器模式
简介:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。也就是不同的数据提供者使用一个适配器来向一个相同的客户提供服务。
如:ListView或GridView的Adapter如我们常见用 BaseAdpter, ArrayAdapter, CursorAdapter,就是用的适配者模式。
4.观察者模式
简介:一个对象发生改变时,所有信赖于它的对象自动做相应改变。
如:android中的Broadercast,广播发出信号,所有接受到广播的都做对应的改变。
观察者模式的核心思想是将数据表示层和逻辑层分离,并定义了稳定的消息传递机制、抽象出调用接口。在需要采用异步通信的应用场景中,合理地运用观察者模式往往会有很好的效果。
5.建造者模式
AlertDialog.Builder
简介:可以分步地构造每一部分。
6.命令模式
Handler.post后Handler.handleMessage
简介:把请求封装成一个对象发送出去,方便定制、排队、取消。
7.享元模式
Message.obtainMessage通过重用Message对象来避免大量的Message对象被频繁的创建和销毁。
简介:运用共享技术有效地支持大量细粒度的对象。
8.迭代器模式
如通过Hashtable.elements方法可以得到一个Enumeration,然后通过这个Enumeration访问Hashtable中的数据,而不用关心Hashtable中的数据存放方式。
简介:提供一个方法顺序访问数据集合中的所有数据而又不暴露对象的内部表示。
9.备忘录模式
Activity的onSaveInstanceState和onRestoreInstanceState就是通过Bundle这种序列化的数据结构来存储Activity的状态,至于其中存储的数据结构,这两个方法不用关心
简介:不需要了解对象的内部结构的情况下备份对象的状态,方便以后恢复。
10.原型模式
比如我们需要一张Bitmap的几种不同格式:ARGB_8888、RGB_565、ARGB_4444、ALAPHA_8等。那我们就可以先创建一个ARGB_8888的Bitmap作为原型,在它的基础上,通过调用Bitmap.copy(Config)来创建出其它几种格式的Bitmap。另外一个例子就是Java中所有对象都有的一个名字叫clone的方法,已经原型模式的代名词了
简介:在系统中要创建大量的对象,这些对象之间具有几乎完全相同的功能,只是在细节上有一点儿差别。
11.代理模式
类似于ios开发的delegate委托模式,所有的AIDL都一个代理模式的例子。假设一个Activity A去绑定一个Service S,那么A调用S中的每一个方法其实都是通过系统的Binder机制的中转,然后调用S中的对应方法来做到的。Binder机制就起到了代理的作用。
简介:为其他对象提供一种代理以控制对这个对象的访问。
12.状态模式
View.onVisibilityChanged方法,就是提供了一个状态模式的实现,允许在View的visibility发生改变时,引发执行onVisibilityChanged方法中的动作。
简介:状态发生改变时,行为改变。
13.策略模式
举例:Java.util.List就是定义了一个增(add)、删(remove)、改(set)、查(indexOf)策略,至于实现这个策略的ArrayList、LinkedList等类,只是在具体实现时采用了不同的算法。但因为它们策略一样,不考虑速度的情况下,使用时完全可以互相替换使用。
简介:定义了一系列封装了算法、行为的对象,他们可以相互替换。
14.调解者模式
简介:一个对象的某个操作需要调用N个对象的M个方法来完成时,把这些调用过程封装起来,就成了一个调解者
举例:如Resource.getDrawable方法的实现逻辑是这样的:创建一个缓存来存放所有已经加载过的,如果getDrawable中传入的id所对应的Drawable以前没有被加载过,那么它就会根据id所对应的资源类型,分别调用XML解析器生成,或者通过读取包中的图片资源文件来创建Drawable。而Resource.getDrawable把涉及到多个对象、多个逻辑的操作封装成一个方法,就实现了一个调解者的角色。