Java 设计模式
# Java 设计模式
# 一、 单例模式
# 1.1 饿汉式
懒汉式的实现思路是:饿汉根本等不及别人来找他,不管三七二十一先初始化了自身的实例,生怕自己饿着了。
类默认先直接初始化一个实例,以后调用 getInstance()
总是返回这个已创建好的实例。
缺点:在没有必要获取实例时,已经预先产生了开销。
优点:规避了懒汉式方法的线程问题,不用显示编写线程安全代码。
类形式:构造方法私有化,公共静态方法返回对象
- 构造私有化
- 类加载执行
- 提供一个公共静态方法供外部方法
package com.singerw.designpatterndemo;
/**
* @Author: CodeSleep
* @Date: 2021-06-21 14:01
* @Description: //TODO 单例模式 ==> 饿汉模式
*/
public class SingIeton {
/**
* 2.声明Singleton2
*/
private static SingIeton s = new SingIeton();
/**
* @Author CodeSleep
* @Date: 2021-06-21 14:03
* @Description: //TODO 1.通过对构造访问权限的控制,我们将方法私有化后,为不能直接new
*/
private SingIeton() {
}
/**
* @return 返回值是SingIeton;返回值是私有属性 SingIeton s
* @Author CodeSleep
* @Date: 2021-06-21 14:16
* @Description: //TODO 3.提供一个公共静态方法供外部方法,
*/
public synchronized static SingIeton getInstance() {
return s;
}
}
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
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
# 1.2 懒汉式
懒汉式的实现思路是:你不找懒汉,懒汉根本就懒得去初始化自己。
instance
初始时没有初始化,只有当第一次调 getInstance()
时才创建实例。
缺点:当有两个线程调 getInstance()
方法,当它们同时执行到 if (null == instance)
这行代码,instance
为 null
。
继续向下执行,会生成两个实例,违背了单例模式的初衷。
package com.singerw.designpatterndemo;
/**
* @Author: CodeSleep
* @Date: 2021-06-21 14:01
* @Description: //TODO 单例模式 ==> 懒汉模式
*/
public class SingIeton2 {
/**
* 2.申明 SingIeton2
*/
private static SingIeton2 s = null;
/**
* @Author CodeSleep
* @Date: 2021-06-21 14:03
* @Description: //TODO 1.通过对构造访问权限的控制,我们将方法私有化后,为不能直接new
*/
private SingIeton2() {
}
/**
* @return 返回值是SingIeton2;返回值是私有属性 SingIeton2 s
* synchronized 支持线程同步
* @Author CodeSleep
* @Date: 2021-06-21 14:13
* @Description: //TODO 3.提供一个公共静态方法供外部方法,
*/
public synchronized static SingIeton2 getInstance() {
// 判断s 是否为Null
if (s == null) {
// 如果为null,则实例化SingIeton2
s = new SingIeton2();
}
return s;
}
}
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
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
# 1.3 静态内部类模式
package com.singerw.designpatterndemo;
/**
* @author Administrator
*/
/**
* @Author: CodeSleep
* @Date: 2021-06-22 9:11
* @Description: //TODO 懒汉方式来实现单例模式 懒加载 (静态内部类)
*
*/
public class SingIeton3 {
/**
* @Author CodeSleep
* @Date: 2021-06-22 9:10
* @Description: //TODO 2 声明 Singleton3
* 外部类加载,这个内部类SingletonHolder ->不执行的 =>依然满足懒加载
*/
private static class SingletonHolder {
//只执行一次
private static SingIeton3 s = new SingIeton3();
}
/**
* @Author CodeSleep
* @Date: 2021-06-22 9:10
* @Description: //TODO 1. 通过对构造访问权限控制,我们将方法私有化后,外部不能直接new .
*/
private SingIeton3() {
System.out.println("private Singleton3");
}
/**
* synchronized 支持线程同步
*
* @return Singleton s
* @Author CodeSleep
* @Date: 2021-06-22 9:09
* @Description: //TODO 3.提供一个公共静态方法供外部访问,返回值类型是Singleton;返回值是私有属性 Singleton s
*/
public static SingIeton3 getInstance() {
//当getInstance被调用的时候(第一次被调用的时候),调用上面的类,那么SingletonHolder就会被加载,进入SingletonHolder静态的实例化
return SingletonHolder.s;
}
}
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
42
43
44
45
46
47
48
49
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
42
43
44
45
46
47
48
49
# 1.4 双重锁的形式
如果既不想在没有调用 getInstance(
) 方法时产生开销,又不想发生线程安全问题,就可以采用双重锁的形式。
public class SyncSingleton {
private SyncSingleton() {
System.out.println("Singleton()");
}
private static SyncSingleton instance = null;
public static SyncSingleton getInstance() {
if (null == instance) {
synchronized(SyncSingleton.class) {
if (null == instance) {
instance = new SyncSingleton();
}
}
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注:在外面判断了 instance 实例是否存在,为什么在锁定后又要在内部又判断一次?
这是因为,如果
instance
为null
时有两个线程同时调用getInstance()
,由于synchronized
机制,只允许一个线程进入,另一个需要等待。这时如果没有第二道
instance
是否为null
的判断,就可能发生第一个线程创建一个实例,而第二个线程又创建一个实例的情况。
# 二、适配器模式
# 三、工厂模式
编辑 (opens new window)