定义
单例模式(Singleton Pattern)是一种比较简单的设计模式,它的定义是:
Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
单例模式的通用UML图如下:
![](https://img.haomeiwen.com/i12070003/1b499a80c1924c85.png)
从图中可以看出,Singleleton是一个单例类,通过private的构造函数来声明一个程序中只产生一个类的对象,并且这个对象是在Singleleton类中自行实例化的在(Singleton中自己使用new Singleton())。单例模式的通用代码如下:
public class Singleton{
private static final Singleton singleton = new Singleton(); //在内部定义一个静态的对象
private Singleton{
//定义私有的构造函数
}
public static singleton getSingleton(){ //调用该方法得到对象
return singleton;
}
public static void doSomething(){
//对象所要操作的动作
}
}
下面利用单例模式的思想来实际编写一个简单的程序:
public class HeadTeacher{
private static final HeadTeacher headteacher = new HeadTeacher(); //建立一个班主任对象
private HeadTeacher{
//定义私有的构造函数
}
public static HeadTeacher getHeadTeacher(){ //得到该对象的方法
return headteacher;
}
public static void say(){
System.out.println("Hello students! I am miss Zhang"); //向学生打招呼
}
}
public class Student{
public static void main(String[] args){
for(int i=0;i<5;i++){ //学生周一到周五到学校上课
HeadTeacher headteacher = HeadTeacher.getHeadTeacher();
headteacher.say(); //班主任向学生打招呼
}
}
}
这个程序是在模仿生活中班主任在每一个工作日向学生打招呼说“Hello students”,这些学生只有一个班主任,因此他们只会听到这位班主任的招呼,而不是其他的班主任。程序的运行结果如下:
![](https://img.haomeiwen.com/i12070003/6ccfe7ee7a057075.png)
应用
单例模式的优点主要有以下几个方面:
(1)由于单例模式在内存中只有一个实例,所以减少了内存开支和系统的性能开销。
(2)单例模式可以避免对资源的多重占用。例如写一个文件动作,由于只有一个实例存在内存中,避免了对同一个资源文件的同时写操作。
(3)单例模式可以在系统设置全局的访问点,优化和共享资源访问。例如可以设计一个单例类来负责所有数据表的映射处理。
综合以上的优点,当我们再设计程序时看到需要在一个系统中,要求一个类有且仅有一个对象并且如果出现多个对象就会出现“不良反应”的需求时,就可以使用单例模式。具体的场景如下:
(1)要求生成唯一序号的环境。
(2)在整个项目中需要一个共享访问点或者共享数据。例如一个Web页面上的一个计数器,可以使用单例模式保持计数器的值,并确保线程是安全的。
(3)创建一个对象消耗过多时。
(4)需要定义大量的静态常量和静态方法的环境时。
注意事项
单例模式也有比较明显的缺点,具体如下:
(1)单例模式一般是没有接口的,扩展会很困难,如果要扩展,除了修改代码基本上就没有其他的办法。
(2)单例模式对于测试是不利的。在实际开发中,加入单例模式没有完成,是无法进行程序测试的,因为它既没有接口也不能用其他方式虚拟一个对象。
(3)在高并发的情况下,需要注意单例模式的线程同步问题。单例模式有着不同的实现方式,上面的“班主任打招呼”的例子是不会产生多个实例情况的,但是在某些情况下是必须要考虑线程同步的,举例来说:
public class Singleton{
private static Singleton singleton = null;
private Singleton(){
//构造函数
}
public static Singleton getSingleton(){ //返回实例
if(singleton=null){
singleton = new Singleton();
}
return singleton;
}
}
在上述代码中是有可能出现线程同步问题的,例如线程A在执行到singleton = new Singleton();
这一步时需要等待JVM来创造一个对象,而在等待的时候线程B也在执行,而且正好执行到了if(singleton=null)
这一步,由于这时候线程A要创建的对象还没有初始化出来,因此线程B在这里获得的判断条件为真,它就会继续执行下去。这样线程A和线程B都创建了一个对象。
扩展
如果一个类需要很多个对象,则直接new就可以了;如果只需要一个对象,就可以直接使用单例模式,但是如果要求一个类只能产生两个或三个对象时,就需要使用单例模式的扩展——多例模式。
多例模式的定义是产生固定数量对象的模式。在多例模式中我们可以在设计时决定在内存中有多少个实例,方便系统进行扩展,修正。例如在读取文件当中,我们可以在系统启动时完成初始化工作,在内存中启动固定数量的reader实例,然后在需要读取文件时就可以快速的响应。
网友评论