在前面的博文中,小编介绍了设计模式中的原型模式,不知道有没有帮助到有需要的小伙伴呢`(*∩_∩*)′,今天这篇博文,小编继续来介绍相关的设计模式,今天要和大家见面的是单例模式,不由得又让小编想起Darry Ring,或许只能想想而已`(*∩_∩*)′,开篇闲扯到这里,接着步入正题,今天这篇博文,小编会从什么是单例模式,为什么要使用单例模式,饿汉式,懒汉式、双重检查以及配之以相关的Demo进行讲解,希望对有需要的小伙伴有帮助,还请小伙伴多多指教。
什么是单例模式
单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象,其实GOF对单例模式的定义是:保证一个类, 只有一个实例存在,同时提供能对该实例加以访问的全局访问方法,我们来看一下单例模式的结构图:
为什么要使用单例模式
在应用系统开发中,我们常常有以下需求
a、在多个线程之间,比如servlet环境,共享同一个资源或者操作同一个对象。
b、在整个程序空间使用全局变量,共享资源。
c、大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。
因为单例模式可以保证为一个类只生成唯一的实例对象,所以这些情况,单例模式就派上用场了。
单例模式的实现
a、饿汉式
b、懒汉式
c、双重检查
首先,我们来实现一个简单的,新建一个java项目,新建Person类,生成get和set方法,保证人只有一个实例,计划生育,响应国家号召是不是`(*∩_∩*)′,编写相关代码,如下所示:
public class Person {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
新建类MainClass,我们可以new多少个对象呢?编写相关代码,如下所示:
public class MainClass {
public static void main(String[] args){
Person per = new Person();
Person per2 = new Person();
per.setName("xiaoding");
per2.setName("dingding");
System.out.println(per.getName());
System.out.println(per2.getName());
}
}
运行,如下所示:
通过Person类,getName得到的是两个name,表明这两个根本就不是一个对象,也就是说,通过person类,我们生成了两个不同的对象,如果是一个的话,她们的名字应该是一样的,我们如何保证只有一个对象呢?我们在MainClass里面new的是她的构造函数,改造Person的代码,把构造函数私有化,代码如下所示:
public class Person {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person(){
}
//提供一个全局的静态方法
public static Person getPerson(){
return new Person();
}
}
改造MainClass的方法,如下所示:
public class MainClass {
public static void main(String[] args){
Person per = Person.getPerson();
Person per2 = Person.getPerson();
per.setName("xiaoding");
per2.setName("dingding");
System.out.println(per.getName());
System.out.println(per2.getName());
}
}
运行,如下所示:
运行还是两个对象,我们如何保证是一个对象呢?如何保证实例化一个对象呢?我们可以采用饿汉式,编写Person的代码部分我们直接通过对象就能调用,如下所示:
public class Person {
public static final Person person = new Person();
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person(){
}
//提供一个全局的静态方法
public static Person getPerson(){
Return person;
}
}
运行,效果如下所示:
这个时候就表示,他们是同一个对象,getPerson的是一个对象,那么什么是懒汉式呢?重新新建一个了Person2,编写相关代码如下所示:
public class Person2 {
private String name;
private static Person2 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person2(){
}
//提供全局的静态方法
public static Person2 getPerson(){
if(person == null){
person = new Person2();
}
return person;
}
}
运行效果如下所示:
这个呢就是所谓的饿汉式,懒汉式类加载的时候直接初始化,如果是多线程,懒汉式是不能保证只有一个实例的,那么我们如何解决这个问题呢?新建类Person3,编写相关代码:
public class Person3 {
private String name;
private static Person3 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person3(){
}
//提供全局的静态方法
public static Person3 getPerson(){
if(person == null){
person = new Person3();
}
return person;
}
}
Person3相对于Person2来说,解决了多线程的问题,接着我们来看双重检查,双重检查,我们来看新建类Person4,编写相关代码,如下所示:
public class Person4 {
private String name;
private static Person4 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//构造函数私有化
private Person4(){
}
//提供全局的静态方法
public static Person4 getPerson(){
if(person == null){
synchronized(Person4.class){
if(person == null){
person = new Person4();
}
}
}
return person;
}
}
小编寄语:该博文,小编主要简单的介绍了单利模式,分别介绍了什么是单例模式、单例模式的结构图、饿汉式、懒汉式、双重检查等方面做了简单的介绍,对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。