3.[研磨设计模式笔记]单例模式

简介:

1.定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2.解决问题

——读取配置文件的内容

不用模式的解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public  class  AppConfig {
     private  String parameterA;
     private  String parameterB;
     public  String getParameterA() {
         return  parameterA;
     }
     public  String getParameterB() {
         return  parameterB;
     }
     public  AppConfig() {
         readConfig();
     }
     private  void  readConfig() {
         Properties p =  new  Properties();
         InputStream in =  null ;
         try  {
             in = AppConfig. class .getResourceAsStream(
                         “AppConfig.properties”);
             p.load(in);
             this .paramterA = p.getProperty(“paramA”);
             this .paramterB = p.getProperty(“paramB”);
         catch (Exception e) {
         finally  {
             try  {
                 in.close();
             catch (Exception e) {
             }
         }
     }
}
public  class  Client {
     public  static  void  main(String[] args) {
         AppConfig Config =  new  AppConfig();
         String paramA = config.getParameterA();
         String paramB = config.getParameterB();
     }
}

使用单例模式来解决问题

(饿汉式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public  class  AppConfig {
     private  static  AppConfig instance =  new  AppConfig();
     public  static  AppConfig() getInstance() {
         return  instance;
     }
     private  String parameterA;
     private  String parameterB;
     public  String getParameterA() {
         return  parameterA;
     }
     public  String getParameterB() {
         return  parameterB;
     }
     private  AppConfig() {
         readConfig();
     }
     private  void  readConfig() {
         Properties p =  new  Properties();
         InputStream in =  null ;
         try  {
             in = AppConfig. class .getResourceAsStream(
                         “AppConfig.properties”);
             p.load(in);
             this .paramterA = p.getProperty(“paramA”);
             this .paramterB = p.getProperty(“paramB”);
         catch (Exception e) {
         finally  {
             try  {
                 in.close();
             catch (Exception e) {
             }
         }
     }
}
public  class  Client {
     public  static  void  main(String[] args) {
         AppConfig Config = AppConfig.getInstance();
         String paramA = config.getParameterA();
         String paramB = config.getParameterB();
     }
}


3.模式讲解

在不用模式的解决方案中,客户端是通过new一个AppConfig的实例来得到一个操作配置文件内容的对象。如果在系统运行中,有很多地方都需要使用配置文件的内容,也就会有很多地方都创建AppConfig对象的实例。这样系统会同时存在多份配置文件的内容,会严重浪费内存资源。

解决思路

分析上面的问题,一个类能够/被创建多个实例,问题在于/类的构造方法是公开的,也就是可以/让类的外部/通过构造方法创建多个实例。要控制一个类/只被创建一个实例,那就是把类的构造函数/私有化,然后由这个类来/提供外部访问/类实例的方法,这就是单例模式的实现方式。

单例模式使用来保证这个类在运行期间只会被创建一个类实例,另外,单例模式还提供一个全局唯一访问这个类实例的访问点,就是getInstance方法。

示例代码

(懒汉式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  class  Singleton {
     //4:定义一个变量来存储创建好的类实例
     //5:因为这个变量要在静态方法中使用,所以需要加上static修饰
     private  static  Singleton instance =  null ;
     //1:私有化构造方法,好在内部控制创建实例的数目
     private  Singleton() {}
     //2:定义一个方法来为客户端提供类实例
     //3:这个方法需要定义成类方法(静态方法),也就是要加static
     public  static  synchronized  Singleton getInstance() {
         //6:判断存储实例的变量是否有值
         if (instance ==  null ) {
             //6.1:如果没有,就创建一个类实例,并把赋值给存储实例的变量
             instance =  new  Singleton();
         }
         //6.2:如果有值,那就直接使用
         return  instance;
     }
}

(饿汉式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Java中 static 的特性:
1 . static 变量在类加载的时候进行初始化。
2 .多个实例的 static 变量会共享同一块内存区域。
* 在Java中 static 变量只会被初始化一次,就是在类加载的时候,而且多个实例都会共享这个内存空间。
/*
public  class  Singleton {
     //4:定义一个变量来存储创建好的类实例
     //直接在这里创建类实例,只能创建一次
     private  static  Singleton instance =  new  Singleton();
     //1:私有化构造方法,好在内部控制创建实例的数目
     private  Singleton() {}
     //2:定义一个方法来为客户端提供类实例
     //3:这个方法需要定义成类方法(静态方法),也就是要加static
     public  static  Singleton getInstance() {
         //5:直接使用以创建好的实例
         return  instance;
     }
}

在懒汉式方案里,强制加上static,并没有使用static的特性;而在饿汉式方案里,是主动加上static,使用了static的特性。

单例模式的懒汉式实现体现了延迟加载的思想,即就是一开始不要加载资源或数据,一直等,等到要使用这个资源或数据才加载,也成Lazy Load。

单例模式的懒汉式实现还体现了缓存的思想,即当某些资源或数据被频繁地使用,而这些资源或数据存储在系统外部(如数据库、硬盘文件等),每次操作这些数据的时候都要去获取。通过把这些数据缓存到内存中,每次操作先到内存里面找,如果有就直接使用,如果没有就去获取,并设置到缓存中,下一次访问的时候就可以直接从内存中获取。

应用范围

Java里面实现单例的是一个虚拟机范围,虚拟机在通过自己的ClassLoader装载饿汉式实现单例类就会创建一个类的实例。

单例模式调用示意图

(懒汉式)

124227675.png

(饿汉式)

124220502.png

单例模式的优缺点

1.时间和空间

懒汉式是典型的时间换空间;

饿汉式是典型的空间换时间。

2.线程安全

不加同步的懒汉式是线程不安全的;

饿汉式是线程安全的。

双重检查加锁

指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样,就只需要同步一次,从而减少多次在同步情况下进行判断浪费的时间。

双重检查加锁的实现使用了一个关键字volatile,意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存的,从而确保多个线程能正确的处理该变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  class  Singleton {
     //对保存实例的变量增加volatile的修饰
     private  volatile  static  Singleton instance =  null ;
         
     private  Singleton() {}
         
     public  static  Singleton getInstance() {
         //先检查实例是否存在,如果不存在才进入下面的同步块
         if (instance ==  null ) {
             //同步块,线程安全地创建实例
             synchronized (Singleton. class ) {
                 //再次检查实例是否存在,如果不存在才真正地创建实例
                 if (instance ==  null ) {
                     instance =  new  Singleton();
                 }
             }
         }
         return  instance;
     }
}


4.思考

单例模式的本质:控制实例数目

何时选用单例模式:

如果当:需要控制一个类实例只能有一个,且客户只能从一个全局访问点控制它时,选用单例模式。










本文转自 LinkedKeeper 51CTO博客,原文链接:http://blog.51cto.com/sauron/1224147,如需转载请自行联系原作者
目录
相关文章
|
25天前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
59 0
|
1月前
|
设计模式 缓存 安全
【设计模式】单例模式:确保类只有一个实例
【设计模式】单例模式:确保类只有一个实例
20 0
|
3月前
|
设计模式 数据库连接 数据库
发挥设计模式单例模式的力量:从技术到社会的转变
发挥设计模式单例模式的力量:从技术到社会的转变
|
3月前
|
设计模式 安全 Java
设计模式-单例模式
设计模式-单例模式
36 0
|
1月前
|
设计模式 安全 Java
设计模式之单例模式
设计模式之单例模式
|
3月前
|
设计模式 缓存 安全
设计模式 - 创建型模式_ 单例模式 Singleton Pattern
设计模式 - 创建型模式_ 单例模式 Singleton Pattern
39 0
|
5天前
|
设计模式 存储 Java
Java设计模式:解释一下单例模式(Singleton Pattern)。
`Singleton Pattern`是Java中的创建型设计模式,确保类只有一个实例并提供全局访问点。它通过私有化构造函数,用静态方法返回唯一的实例。类内静态变量存储此实例,对外仅通过静态方法访问。
12 1
|
1月前
|
设计模式 存储 缓存
设计模式之单例模式(C++)
设计模式之单例模式(C++)
21 2
|
1月前
|
设计模式 安全 Java
Java设计模式之单例模式
在软件工程中,单例模式是一种常用的设计模式,其核心目标是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。Java作为一门广泛使用的编程语言,实现单例模式是面试和实际开发中的常见需求。
66 9
Java设计模式之单例模式
|
2月前
|
设计模式 存储 安全
【设计模式】创建型模式之单例模式(Golang实现)
【2月更文挑战第3天】一个类只允许创建一个对象或实例,而且自行实例化并向整个系统提供该实例,这个类就是一个单例类,它提供全局访问的方法。这种设计模式叫单例设计模式,简称单例模式。
34 1