设计模式(1)——单例模式
# 基本思想和原则
保证一个类仅有一个实例,自行实例化并提供一个访问它的全局访问点。
单例模式有以下三个要素:
- 保证类实例的唯一性。
- 提供一个获取类唯一实例的全局访问点。
- 类必须自行创建这个唯一的实例,不能由用户手动创建。
# 动机
在一些情况下我们希望某个类在系统中有且仅有一个实例,常见的例子有全局 id 生成器、任务管理器、全局计时器、配置对象等。如果这些类的对象有多个,可能造成数据不一致的情况,因此需要一种通用的模式来保证这些类在系统中有且仅有一个实例。
# 单例模式存在意义
模式特点:
保证类仅有一个实例,并提供一个访问它的全局访问点。
- 设计模式在所有语言内都是通用的
- 设计模式存在的意义就是让代码设计结构设计的更好
# 实例代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server
class ConnectionPool:
__instance = None
def __init__(self):
self.ip = "1.1.1.1"
self.port = 3306
self.pwd = "123123"
self.username = 'xxxx'
# 去连接
self.conn_list = [1,2,3,4,5,6,7,8,9, 10]
@staticmethod
def get_instance():
if ConnectionPool.__instance:
return ConnectionPool.__instance
else:
# 创建一个对象,并将对象赋值给静态字段 __instance
ConnectionPool.__instance = ConnectionPool()
return ConnectionPool.__instance
def get_connection(self):
# 获取连接
import random
r = random.randrange(1,11)
return r
def index():
# p = ConnectionPool()
# print(p)
p = ConnectionPool.get_instance()
conn = p.get_connection()
return "iiiiiii" + str(conn)
def news():
return 'nnnnnnn'
def RunServer(environ, start_response):
start_response(status='200 OK', headers=[('Content-Type', 'text/html')])
url = environ['PATH_INFO']
if url.endswith('index'):
ret = index()
return ret
elif url.endswith('news'):
ret = news()
return ret
else:
return "404"
if __name__ == '__main__':
httpd = make_server('', 80, RunServer)
print("Serving HTTP on port 80...")
httpd.serve_forever()
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
50
51
52
53
54
55
56
57
58
59
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
50
51
52
53
54
55
56
57
58
59
单例模式的实现可以分为懒汉式和饿汉式两种,懒汉式指的是等到需要的时候再创建对象,饿汉式则是在类被加载时就创建一个对象。因此懒汉式存在线程安全的问题,而饿汉式没有线程安全问题。
我们先来看懒汉式:
public class Singleton {
private Singleton() {}
private static Singleton _instcance = null;
public static Singleton getInstance() {
if (_instcance == null) {
_instcance = new Singleton();
}
return _instcance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
上面的方式不是线程安全的,如果想要线程安全,可以使用同步:
public class Singleton {
private Singleton() {}
private static Singleton _instcance = null;
public static synchronized Singleton getInstance() {
if (_instcance == null) {
_instcance = new Singleton();
}
return _instcance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
这种方式将整个getInstance
方法同步了,因此每次调用的时候都要同步,效率比较低。还可以只在第一次的时候同步:
public class Singleton {
private Singleton() {}
private static Singleton _instcance = null;
public static Singleton getInstance() {
if (_instcance == null) {
synchronized(Singleton.class){
if (_instcance == null) {
_instcance = new Singleton();
}
}
}
return _instcance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上面这种方式只在第一次的时候同步,当已经存在实例时直接返回。
还可以使用静态内部类实现单例:
public class Singleton {
private static class InnerClass{
private static final Singleton _instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return InnerClass._instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
静态内部类也不需要同步,因为在类加载的时候就创建了实例。
主函数如下:
public class Test {
public static void main(String[] args) {
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
System.out.println(obj1.hashCode());
System.out.println(obj2.hashCode());
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
打印的结果是obj1
和obj2
的hashCode
相同(每次运行得到的hashCode
不同):
1761291320
1761291320
1
2
2
编辑 (opens new window)
上次更新: 2024-02-28, 07:14:58