SINGLETON(单件)—对象创建型模式

1. 意图

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

2. 动机

    对一些类来说,只有一个实例是很重要的。虽然系统中可以有许多打印机,但却只应该有一个打印假脱机(printer spooler),只应该有一个文件系统和一个窗口管理器。一个数字滤波器只能有一个A / D转换器。一个会计系统只能专用于一个公司。

    我们怎么样才能保证一个类只有一个实例并且这个实例易于被访问呢?一个全局变量使得一个对象可以被访问,但它不能防止你实例化多个对象。一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。这就是S i n g l e t o n模式。

3. 适用性

    在下面的情况下可以使用S i n g l e t o n模式

当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

适用场景:

    将来系统是高并发的,比如dbinfo,数据库信息放在配置文件里面,高并发作用是只读取一次配置文件。

    dbinfo

    servlet

    监听器

    过滤器

注:request和response不是单例对象。每个人访问的都是同一个servlet,但是不同在于,每个人的请求request是不同的,request对象是servlet容器创建的。request对象跟HTTP请求绑定在一起的,一个HTTP请求绑定一个request。

application是一个全局变量,也是一个单例对象。

4. 结构

5. 参与者

S i n g l e t o n

— 定义一个 I n s t a n c e操作,允许客户访问它的唯一实例。 I n s t a n c e是一个类操作(即

S m a l l t a l k中的一个类方法和C + +中的一个静态成员函数)。

— 可能负责创建它自己的唯一实例。

6. 协作

客户只能通过S i n g l e t o n的I n s t a n c e操作访问一个S i n g l e t o n的实例。

7.实现

常见单例的两种写法:

写法一:

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
public 
class 
ConnectionFactory {
     
    
private 
static 
ConnectionFactory factory;                    
//单例对象
    
private 
DbInfo dbinfo;
     
    
private 
ConnectionFactory(DbInfo dbinfo){
            
this
.dbinfo = dbinfo;
    
}
     
    
public 
static 
ConnectionFactory instance(){
        
if
(factory == 
null
){ 
            
DbInfo dbinfo = DbInfo.instance();
            
factory = 
new 
ConnectionFactory(dbinfo);        
        
}
        
return 
factory;
    
}
     
    
/**
     
* 打开一个数据库连接
     
* @return
     
*/
    
public 
DbConnection openConnection(){
        
DbConnection connection;
        
if
(
this
.dbinfo.getDriver().equals(
"oracle"
)){
            
connection = 
new 
OracleConnection(factory);
        
}
else
{
            
connection = 
new 
MysqlConnection(factory);
        
}
         
        
return 
connection;
    
}  
     
}

写法二:

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
public 
class 
ConnectionFactory2 {
     
    
private 
static 
ConnectionFactory2 factory;              
//1.要有单例对象
     
    
private 
ConnectionFactory2(){
         
    
}
     
    
static
{
         
        
factory = 
new 
ConnectionFactory2();
         
    
}
     
    
public 
static 
DbConnection openConnection(){
         
        
DbConnection connection;
         
        
DbInfo dbinfo = DbInfo.instance();
        
if
(dbinfo.getDriver().equals(
"oracle"
)){
            
connection = 
new 
OracleConnection(factory);
        
}
else
{
            
connection = 
new 
MysqlConnection(factory);
        
}
         
        
return 
connection;    
         
    
}
}


线程相关单例写法:

//饿汉式。(常用)

1
2
3
4
5
6
7
8
9
class 
Single
{
    
private 
static 
final 
Single s = 
new 
Single();
    
private 
Single(){}
    
public 
static 
Single getInstance()
    
{
        
return 
s;
    
}
}

//懒汉式(延迟加载单例设计模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
class 
Single{
    
private 
static 
Single s = 
null
;
    
private 
Single(){}
    
public 
static  
Single getInstance(){
        
if
(s==
null
){       
//多重判断
            
synchronized
(Single.
class
){     
//注意锁的用法
                
if
(s==
null
)
                    
s = 
new 
Single();
            
}
        
}
        
return 
s;
    
}
}

单例模式有以下特点:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

8.将数据库配置文件(文件配置,xml配置)内容解析到单例对象中

01.解析配置文件

    配置文件

1
2
3
4
dbURL=jdbc:oracle:thin:
@10
.0.
19.252
:
1521
:orcl
dbDriver=oracle.jdbc.driver.OracleDriver
username=moto
password=
123456

    单例类

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
public 
class 
DbInfo {
    
private 
static 
DbInfo dbInfo;                      
//单例对象
    
private 
String dbURL;
    
private 
String dbDriver;
    
private 
String username;
    
private 
String password;
     
    
private 
DbInfo(){
         
    
}
     
    
public 
static 
DbInfo instance() 
throws 
Exception{
        
if
(dbInfo == 
null
){
            
dbInfo = 
new 
DbInfo();
            
dbInfo.init();
        
}  
         
        
return 
dbInfo;
    
}
     
    
/**
     
* 读取配置文件,给属性初始化
     
*/
    
private 
void 
init() 
throws 
Exception {
        
Properties prop = 
new 
Properties();
        
String path = DbInfo.
class
.getResource(
"/"
).getPath() + 
"db.properties"
;
        
prop.load(
new 
FileInputStream(
new 
File(path)));
        
this
.dbDriver = prop.getProperty(
"dbDriver"
);
        
this
.dbURL = prop.getProperty(
"dbURL"
);
        
this
.password = prop.getProperty(
"password"
);
        
this
.username = prop.getProperty(
"username"
);
    
}
 
    
public 
String getDbURL() {
        
return 
dbURL;
    
}  
 
    
public 
String getDbDriver() {
        
return 
dbDriver;
    
}
     
    
public 
String getUsername() {
        
return 
username;
    
}  
 
    
public 
String getPassword() {
        
return 
password;
    
}
 
}

02.解析xml文件

    xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version=
"1.0" 
encoding=
"UTF-8"
?>
<config>
 
<dbinfo>
   
<dbUrl>jdbc:oracle:thin:
@10
.0.
19.252
:
1521
:orcl</dbUrl>
   
<dbDriver>oracle.jdbc.driver.OracleDriver</dbDriver>
   
<username>moto</username>
   
<password>
123456
</password>
</dbinfo>
 
<DbInfo dbUrl=
"jdbc:oracle:thin:@10.0.19.252:1521:orcl"  
dbDriver=
"oracle.jdbc.driver.OracleDriver"
       
username=
"moto" 
password=
"123456"
></DbInfo>
        
</config>

    单例类

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
public 
class 
DbInfo2 {
     
    
private 
static 
DbInfo2 dbInfo;                      
//单例对象
    
private 
String dbURL;
    
private 
String dbDriver;
    
private 
String username;
    
private 
String password;
    
private 
Document document;
     
    
private 
DbInfo2(){
         
    
}
     
    
public 
static 
DbInfo2 instance() 
throws 
Exception{
        
if
(dbInfo == 
null
){
            
dbInfo = 
new 
DbInfo2();
            
dbInfo.init();
        
}  
         
        
return 
dbInfo;
    
}
     
    
/**
     
* 读取配置文件,给属性初始化
     
*/
    
private 
void 
init() 
throws 
Exception {
         
        
String path = DbInfo.
class
.getResource(
"/"
).getPath() + 
"config.xml"
;
        
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        
DocumentBuilder db = dbf.newDocumentBuilder();
        
document = db.parse(
new 
File(path));                             
//解析XML文件  
        
Node node = document.getElementsByTagName(
"DbInfo"
).item(
0
);
        
Element element = (Element)node;
        
dbURL = element.getAttribute(
"dbUrl"
);
        
dbDriver = element.getAttribute(
"dbDriver"
);
        
this
.username = element.getAttribute(
"username"
);
        
this
.password = element.getAttribute(
"password"
);
    
}
 
    
public 
String getDbURL() {      
        
return 
dbURL;
    
}  
 
    
public 
String getDbDriver() {
        
return 
dbDriver;
    
}
     
    
public 
String getUsername() {
        
return 
username;
    
}  
 
    
public 
String getPassword() {
        
return 
password;
    
}
 
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 读取配置文件,给属性初始化
*/
//解析
//<DbInfo dbUrl="jdbc:oracle:thin:@10.0.19.252:1521:orcl"  dbDriver="oracle.jdbc.driver.OracleDriver"
//       username="moto" password="123456"></DbInfo>
private 
void 
init() 
throws 
Exception {
         
    
String path = DbInfo.
class
.getResource(
"/"
).getPath() + 
"config.xml"
;
    
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    
DocumentBuilder db = dbf.newDocumentBuilder();
    
document = db.parse(
new 
File(path));                             
//解析XML文件  
    
Node node = document.getElementsByTagName(
"DbInfo"
).item(
0
);
    
Element element = (Element)node;
    
dbURL = element.getAttribute(
"dbUrl"
);
    
dbDriver = element.getAttribute(
"dbDriver"
);
    
this
.username = element.getAttribute(
"username"
);
    
this
.password = element.getAttribute(
"password"
);
}