1. 說(shuō)明
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名、虛擬空間、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、秦皇島網(wǎng)站維護(hù)、網(wǎng)站推廣。
1)單例模式:確保一個(gè)類(lèi)只有一個(gè)實(shí)例,自行實(shí)例化并向系統(tǒng)提供這個(gè)實(shí)例
2)單例模式分類(lèi)此亂:餓單例模式激此(類(lèi)加載時(shí)實(shí)例化一個(gè)對(duì)象給自己的引用),懶單例模式(調(diào)用取得實(shí)例的方法如getInstance時(shí)才會(huì)實(shí)例化對(duì)象)(java中餓單例模式性能優(yōu)于懶單例模式,c++中森鉛檔一般使用懶單例模式)
3)單例模式要素:
a)私有構(gòu)造方法
b)私有靜態(tài)引用指向自己實(shí)例
c)以自己實(shí)例為返回值的公有靜態(tài)方法
2.實(shí)例
餓單例模式:
復(fù)制代碼代碼如下:
package com.wish.modedesign;
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return instance;
}
java中單例模式是一種常見(jiàn)的設(shè)計(jì)模式,單例模式分三種:懶漢式單例、餓漢式單例、登記式單例三種。
單例模式有一下特點(diǎn):
1、單例類(lèi)只能有一個(gè)實(shí)例。
2、單例類(lèi)必須自己自己創(chuàng)建自己的唯一實(shí)例。
3、單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例。
單例模式確保某個(gè)類(lèi)只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對(duì)象、對(duì)話框、打印機(jī)、顯卡的驅(qū)動(dòng)程序?qū)ο蟪1辉O(shè)計(jì)成單例。這些應(yīng)用都或多或少具有資源管理器的功能。每臺(tái)計(jì)算機(jī)可以有若干個(gè)打印機(jī),但只能有一個(gè)Printer Spooler,以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中。每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用。總之,選擇單例模式就是為了避免不一致?tīng)顟B(tài),避免政出多頭。
首先看一個(gè)經(jīng)典的單例實(shí)現(xiàn)。
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// Other methods...
}
Singleton通過(guò)將構(gòu)造方法限定為private避免了類(lèi)在外部被實(shí)例化,在同一個(gè)虛擬機(jī)范圍內(nèi),Singleton的唯一實(shí)例只能通過(guò)getInstance()方法訪問(wèn)。(事實(shí)上,通過(guò)Java反射機(jī)制是能夠?qū)嵗瘶?gòu)造方法為private的類(lèi)的,那基本上會(huì)使所有的Java單例實(shí)現(xiàn)失效。此問(wèn)題在此處不做討論,姑且掩耳盜鈴地認(rèn)為反射機(jī)制不存在。)
但是以上實(shí)現(xiàn)沒(méi)有考慮線程安全問(wèn)題。所謂線程安全是指:如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安族碼全的。或者說(shuō):一個(gè)類(lèi)或者程序所提供的接口對(duì)于線程來(lái)說(shuō)是原子兆好哪操作或者多個(gè)線程之間的切換不會(huì)導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性,也就是說(shuō)我們不用考慮同步的問(wèn)題。顯然以上實(shí)現(xiàn)并不襪悶滿足線程安全的要求,在并發(fā)環(huán)境下很可能出現(xiàn)多個(gè)Singleton實(shí)例。
//////////////////////////////////////////////////////////////////////
驗(yàn)證單例模式的示例
//////////////////////////////////////////////////////////////////////
public class TestStream {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 該類(lèi)只能有一個(gè)實(shí)例
private TestStream() {
} // 私有無(wú)參構(gòu)造方法
// 該類(lèi)必須自行創(chuàng)建
// 有2種方式
private static TestStream ts1 = null;
// 這個(gè)類(lèi)必須自動(dòng)向整個(gè)系統(tǒng)提供這個(gè)實(shí)例對(duì)象
public static TestStream getTest() {
if (ts1 == null) {
ts1 = new TestStream();
}
return ts1;
}
public void getInfo() {
System.out.println("output message " + name);
}
public static void main(String[] args) {
TestStream s = TestStream.getTest();
s.setName("張孝祥 1");
System.out.println(s.getName());
TestStream s1 = TestStream.getTest();
s1.setName("張孝祥 2");
System.out.println(s1.getName());
s.getInfo();
s1.getInfo();
if (s == s1) {
System.out.println("創(chuàng)建的是同一個(gè)實(shí)例");
} else if (s != s1) {
System.out.println("創(chuàng)建的不是同一個(gè)實(shí)例");
} else {
System.out.println("application error");
}
}
}
////////////////////////////////////////////
單例模式(Singleton) ,屬于最常見(jiàn)的設(shè)計(jì)模式之一,大部分系統(tǒng)都會(huì)用到,目的是為了維護(hù)系統(tǒng)中唯一的一個(gè)實(shí)例。
可分為鄭猛eager模式,示例代碼如下:
Java代碼
1.class EagerSingleton{
2. private static final EagerSingleton m_instance = new EagerSingleton();
3. private EagerSingleton(){}
4. public static EagerSingleton getInstance(){
5. return m_instance;
6. }
7.}
class EagerSingleton{
private static final EagerSingleton m_instance = new EagerSingleton();
private EagerSingleton(){}
public static EagerSingleton getInstance(){
return m_instance;
}
}
和 lazy模式,示例代碼如下:
Java代碼
1.class LazySingleton{
2. private static LazySingleton m_instance = null;
3. private LazySingleton(){}
4. public synchronized static getInstance(){
5. if(m_instance == null){
6. m_instance = new LazySingleton();
7. }
8. return m_instance;
9. }
10.}
class LazySingleton{
private static LazySingleton m_instance = null;
private LazySingleton(){}
public synchronized static getInstance(){
if(m_instance == null){
m_instance = new LazySingleton();
喊枝橋 }
return m_instance;
}
}
java源碼中,Runtime.getRuntime()就是單例的一個(gè)例子。
單例模式的精神就是整個(gè)系統(tǒng)中維護(hù)一個(gè)實(shí)例,推廣開(kāi)來(lái),如果在一個(gè)系統(tǒng)搭襪中需要維護(hù)多個(gè)示例,那么就產(chǎn)生了多例模式(multiton)。
多例模式(Multiton) ,通過(guò)聚集對(duì)象了保留自身的多個(gè)示例,根據(jù)客戶端的參數(shù)返回所需要的實(shí)例。
示例代碼如下:
Java代碼
1.class Multiton{
2. private final int INSTANCE_SIZE = 10;
3. private static Map instances = new HashMap(INSTANCE_SIZE);
4. private String name;
5. private Multiton(){}
6. private Multiton(String name){
7. this.name = name;
8. }
9. public synchronized static getInstance(String name){
10. if(instances.containsKey(name)){
11. return instances.get(name);
12. }
13. else{
14. ins = new Multiton(name);
15. instances.put(name, ins);
16. return ins;
17. }
18. }
19.}
class Multiton{
private final int INSTANCE_SIZE = 10;
private static Map instances = new HashMap(INSTANCE_SIZE);
private String name;
private Multiton(){}
private Multiton(String name){
this.name = name;
}
public synchronized static getInstance(String name){
if(instances.containsKey(name)){
return instances.get(name);
}
else{
ins = new Multiton(name);
instances.put(name, ins);
return ins;
}
}
}
[nextpage]
一個(gè)實(shí)用的例子就是KeyGenerator, 示例代碼如下:
Java代碼
1.class KeyGenerator{
2. private final int POOL_SIZE = 20;
3. private static Map instances = new HashMap(16);
4. private KeyInfo keyinfo;
5. private KeyGenerator(){}
6. private KeyGenerator(String keyName){
7. this.keyinfo = new KeyInfo(POOL_SIZE, keyName);
8. }
9. public synchronized static getInstance(String keyName){
10. if(instances.containsKey(keyName)){
11. return (KeyGenerator)instances.get(keyName);
12. }
13. else{
14. keyGen = new KeyGenerator(keyName);
15. instances.put(name, keyGen);
16. return keyGen;
17. }
18. }
19. public synzhronized int getNextKey(){
20. return keyinfo.getNextKey();
21. }
22. }
class KeyGenerator{
private final int POOL_SIZE = 20;
private static Map instances = new HashMap(16);
private KeyInfo keyinfo;
private KeyGenerator(){}
private KeyGenerator(String keyName){
this.keyinfo = new KeyInfo(POOL_SIZE, keyName);
}
public synchronized static getInstance(String keyName){
if(instances.containsKey(keyName)){
return (KeyGenerator)instances.get(keyName);
}
else{
keyGen = new KeyGenerator(keyName);
instances.put(name, keyGen);
return keyGen;
}
}
public synzhronized int getNextKey(){
return keyinfo.getNextKey();
}
}
作為對(duì)象的創(chuàng)建模式[GOF ] 單例模式確保某一個(gè)類(lèi)只有一個(gè)實(shí)例 而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例 這個(gè)類(lèi)稱為單例類(lèi)
單例模式的要點(diǎn)
單例單例
顯然單例模式的要點(diǎn)有三個(gè) 一是某各類(lèi)只能有一個(gè)實(shí)例 二是它必須自行創(chuàng)建這個(gè)事例 三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例 在下面的對(duì)象圖中 有一個(gè) 單例對(duì)象 而 客戶甲 客戶乙 和 客戶丙 是單例對(duì)象的三個(gè)客戶對(duì)象 可以看到 所有的客戶對(duì)象共享一個(gè)單例對(duì)象 而且從單例對(duì)象到自身的連接線可以看出 單例對(duì)象持有對(duì)自己的引用
資源管理
一些資源管理器常常設(shè)計(jì)成單例模式
在計(jì)算機(jī)系統(tǒng)中 需要管理的資源包括軟件外部資源 譬如每臺(tái)計(jì)算機(jī)可以有若干個(gè)打印機(jī) 但只能有一個(gè)Printer Spooler 以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中 每臺(tái)計(jì)算機(jī)可以有若干傳真卡 但是只應(yīng)該有一個(gè)軟件負(fù)責(zé)管理傳真卡 以避免出現(xiàn)兩份傳真作業(yè)同時(shí)傳到傳真卡中的情況 每臺(tái)計(jì)算機(jī)可以有若干通信端口 系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口 以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用
需要管理的資源包括軟件內(nèi)部資源 譬如 大多數(shù)的軟件都有一個(gè)(甚至多個(gè))屬性(properties)文件存放系統(tǒng)配置 這樣的系統(tǒng)應(yīng)當(dāng)由一個(gè)對(duì)象來(lái)管理一個(gè)屬性文件
需要管理的軟件內(nèi)部資源也包括譬如負(fù)責(zé)記錄網(wǎng)站來(lái)訪人數(shù)的部件 記錄軟件系統(tǒng)內(nèi)部事件 出錯(cuò)信息的部件 或是對(duì)系統(tǒng)的表現(xiàn)進(jìn)行檢查的部件等 這些部件都必須集中管理 不可政出多頭
這些資源管理器構(gòu)件必須只有一個(gè)實(shí)例 這是其一 它們必須自行初始化 這是其二 允許整個(gè)系統(tǒng)訪問(wèn)自己這是其三 因此 它們都滿足單例模式的條件 是單例模式的應(yīng)用
一個(gè)例子 Windows 回收站
Windows x 以后的視窗系統(tǒng)中都有一個(gè)回收站 下圖就顯示了Windows 的回收站
在整個(gè)視窗系統(tǒng)中 回收站只能有一個(gè)實(shí)例 整個(gè)系統(tǒng)都使用這個(gè)惟一的實(shí)例 而且回收站自行提供自己的實(shí)例 因此 回收站是單例模式的應(yīng)用
雙重檢查成例
在本章最后的附錄里研究了雙重檢查成例 雙重檢查成例與單例模式并無(wú)直接的關(guān)系 但是由于很多C 語(yǔ)言設(shè)計(jì)師在單例模式里面使用雙重檢查成例 所以這一做法也被很多Java 設(shè)計(jì)師所模仿 因此 本書(shū)在附錄里提醒讀者 雙重檢查成例在Java 語(yǔ)言里并不能成立 詳情請(qǐng)見(jiàn)本章的附錄
單例模式的結(jié)構(gòu)
單例模式有以下的特點(diǎn)
…… 單例類(lèi)只可有一個(gè)實(shí)例
…… 單例類(lèi)必須自己創(chuàng)建自己這惟一的實(shí)例
…… 單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例
雖然單例模式中的單例類(lèi)被限定只能有一個(gè)實(shí)例 但是單例模式和單例類(lèi)可以很容易被推廣到任意且有限多個(gè)實(shí)例的情況 這時(shí)候稱它為多例模式(Multiton Pattern) 和多例類(lèi)(Multiton Class) 請(qǐng)見(jiàn) 專(zhuān)題 多例(Multiton )模式與多語(yǔ)言支持 一章 單例類(lèi)的簡(jiǎn)略類(lèi)圖如下所示
由于Java 語(yǔ)言的特點(diǎn) 使得單例模式在Java 語(yǔ)言的實(shí)現(xiàn)上有自己的特點(diǎn) 這些特點(diǎn)主要表現(xiàn)在單例類(lèi)如何將自己實(shí)例化上
餓漢式單例類(lèi)餓漢式單例類(lèi)是在Java 語(yǔ)言里實(shí)現(xiàn)得最為簡(jiǎn)便的單例類(lèi) 下面所示的類(lèi)圖描述了一個(gè)餓漢式單例類(lèi)的典型實(shí)現(xiàn)
從圖中可以看出 此類(lèi)已經(jīng)自已將自己實(shí)例化
代碼清單 餓漢式單例類(lèi)
public class EagerSingleton { private static final EagerSingleton m_instance = new EagerSingleton() /** * 私有的默認(rèn)構(gòu)造子*/ private EagerSingleton() { } /** * 靜態(tài)工廠方法*/ public static EagerSingleton getInstance()
{
Java 與模式return m_instance }
讀者可以看出 在這個(gè)類(lèi)被加載時(shí) 靜態(tài)變量m_instance 會(huì)被初始化 此時(shí)類(lèi)的私有構(gòu)造子會(huì)被調(diào)用 這時(shí)候 單例類(lèi)的惟一實(shí)例就被創(chuàng)建出來(lái)了
Java 語(yǔ)言中單例類(lèi)的一個(gè)最重要的特點(diǎn)是類(lèi)的構(gòu)造子是私有的 從而避免外界利用構(gòu)造子直接創(chuàng)建出任意多的實(shí)例 值得指出的是 由于構(gòu)造子是私有的 因此 此類(lèi)不能被繼承
懶漢式單例類(lèi)
與餓漢式單例類(lèi)相同之處是 類(lèi)的構(gòu)造子是私有的 與餓漢式單例類(lèi)不同的是 懶漢式單例類(lèi)在第一次被引用時(shí)將自己實(shí)例化 如果加載器是靜態(tài)的 那么在懶漢式單例類(lèi)被加載時(shí)不會(huì)將自己實(shí)例化 如下圖所示 類(lèi)圖中給出了一個(gè)典型的餓漢式單例類(lèi)實(shí)現(xiàn)
代碼清單 懶漢式單例類(lèi)
package javapatterns singleton demos public class LazySingleton { private static LazySingleton m_instance = null /** * 私有的默認(rèn)構(gòu)造子 保證外界無(wú)法直接實(shí)例化*/ private LazySingleton() { } /** * 靜態(tài)工廠方法 返還此類(lèi)的惟一實(shí)例*/ synchronized public static LazySingleton getInstance()
{ if (m_instance == null)
{ m_instance = new LazySingleton() } return m_instance }
讀者可能會(huì)注意到 在上面給出懶漢式單例類(lèi)實(shí)現(xiàn)里對(duì)靜態(tài)工廠方法使用了同步化 以處理多線程環(huán)境 有些設(shè)計(jì)師在這里建議使用所謂的 雙重檢查成例 必須指出的是 雙重檢查成例 不可以在Java 語(yǔ)言中使用 不十分熟悉的讀者 可以看看后面給出的小節(jié)
同樣 由于構(gòu)造子是私有的 因此 此類(lèi)不能被繼承 餓漢式單例類(lèi)在自己被加載時(shí)就將自己實(shí)例化 即便加載器是靜態(tài)的 在餓漢式單例類(lèi)被加載時(shí)仍會(huì)將自己實(shí)例化 單從資源利用效率角度來(lái)講 這個(gè)比懶漢式單例類(lèi)稍差些
從速度和反應(yīng)時(shí)間角度來(lái)講 則比懶漢式單例類(lèi)稍好些 然而 懶漢式單例類(lèi)在實(shí)例化時(shí) 必須處理好在多個(gè)線程同時(shí)首次引用此類(lèi)時(shí)的訪問(wèn)限制問(wèn)題 特別是當(dāng)單例類(lèi)作為資源控制器 在實(shí)例化時(shí)必然涉及資源初始化 而資源初始化很有可能耗費(fèi)時(shí)間 這意味著出現(xiàn)多線程同時(shí)首次引用此類(lèi)的機(jī)率變得較大
餓漢式單例類(lèi)可以在Java 語(yǔ)言內(nèi)實(shí)現(xiàn) 但不易在C++ 內(nèi)實(shí)現(xiàn) 因?yàn)殪o態(tài)初始化在C++ 里沒(méi)有固定的順序 因而靜態(tài)的m_instance 變量的初始化與類(lèi)的加載順序沒(méi)有保證 可能會(huì)出問(wèn)題 這就是為什么GoF 在提出單例類(lèi)的概念時(shí) 舉的例子是懶漢式的 他們的書(shū)影響之大 以致Java 語(yǔ)言中單例類(lèi)的例子也大多是懶漢式的 實(shí)際上 本書(shū)認(rèn)為餓漢式單例類(lèi)更符合Java 語(yǔ)言本身的特點(diǎn)
登記式單例類(lèi)
登記式單例類(lèi)是GoF 為了克服餓漢式單例類(lèi)及懶漢式單例類(lèi)均不可繼承的缺點(diǎn)而設(shè)計(jì)的 本書(shū)把他們的例子翻譯為Java 語(yǔ)言 并將它自己實(shí)例化的方式從懶漢式改為餓漢式 只是它的子類(lèi)實(shí)例化的方式只能是懶漢式的 這是無(wú)法改變的 如下圖所示是登記式單例類(lèi)的一個(gè)例子 圖中的關(guān)系線表明 此類(lèi)已將自己實(shí)例化
代碼清單 登記式單例類(lèi)
import java util HashMap public class RegSingleton { static private HashMap m_registry = new HashMap() static { RegSingleton x = new RegSingleton() m_registry put( x getClass() getName() x) } /** * 保護(hù)的默認(rèn)構(gòu)造子*/ protected RegSingleton() {} /** * 靜態(tài)工廠方法 返還此類(lèi)惟一的實(shí)例*/ static public RegSingleton getInstance(String name)
{ if (name == null)
{ name = javapatterns singleton demos RegSingleton } if (m_registry get(name) == null)
{ try { m_registry put( name Class forName(name) newInstance() ) } catch(Exception e)
{ System out println( Error happened ) } return (RegSingleton) (m_registry get(name) ) } /** * 一個(gè)示意性的商業(yè)方法*/ public String about()
{ return Hello I am RegSingleton }它的子類(lèi)RegSingletonChild 需要父類(lèi)的幫助才能實(shí)例化 下圖所示是登記式單例類(lèi)子類(lèi)的一個(gè)例子 圖中的關(guān)系表明 此類(lèi)是由父類(lèi)將子類(lèi)實(shí)例化的
下面是子類(lèi)的源代碼
代碼清單 登記式單例類(lèi)的子類(lèi)
import java util HashMap public class RegSingletonChild extends RegSingleton { public RegSingletonChild() {} /** * 靜態(tài)工廠方法*/ static public RegSingletonChild getInstance()
{ return (RegSingletonChild)
RegSingleton getInstance( javapatterns singleton demos RegSingletonChild ) } /** * 一個(gè)示意性的商業(yè)方法*/ public String about()
{ return Hello I am RegSingletonChild }
在GoF 原始的例子中 并沒(méi)有g(shù)etInstance() 方法 這樣得到子類(lèi)必須調(diào)用的getInstance(String name)方法并傳入子類(lèi)的名字 因此很不方便 本章在登記式單例類(lèi)子類(lèi)的例子里 加入了getInstance() 方法 這樣做的好處是RegSingletonChild 可以通過(guò)這個(gè)方法 返還自已的實(shí)例 而這樣做的缺點(diǎn)是 由于數(shù)據(jù)類(lèi)型不同 無(wú)法在RegSingleton 提供這樣一個(gè)方法 由于子類(lèi)必須允許父類(lèi)以構(gòu)造子調(diào)用產(chǎn)生實(shí)例 因此 它的構(gòu)造子必須是公開(kāi)的 這樣一來(lái) 就等于允許了以這樣方式產(chǎn)生實(shí)例而不在父類(lèi)的登記中 這是登記式單例類(lèi)的一個(gè)缺點(diǎn)
lishixinzhi/Article/program/Java/gj/201311/27416
當(dāng)前標(biāo)題:java單列模式代碼 java的單例模式
轉(zhuǎn)載來(lái)于:http://www.chinadenli.net/article28/ddpepcp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、網(wǎng)站導(dǎo)航、網(wǎng)頁(yè)設(shè)計(jì)公司、品牌網(wǎng)站設(shè)計(jì)、動(dòng)態(tài)網(wǎng)站、企業(yè)網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)