單例模式的關鍵有兩點:
1.構造方法為私有,這樣外界就不能隨意調用。
2.get的方法為靜態,由類直接調用
多例模式(Multiton)
1 、多例類可以有多個實例
2 、多例類必須能夠自我創建並管理自己的實例,並向外界提供自己的實例。
一、單例模式和多例模式說明:
1. 單例模式和多例模式屬於對象模式。
2. 單例模式的對象在整個系統中只有一份,多例模式可以有多個實例。
3. 它們都不對外提供構造方法,即構造方法都為私有。
單例模式的三種形式:
第一種形式:懶漢式
public class SingletonClass{
private static SingletonClass instance=null;
public static synchronized SingletonClass getInstance()
{
if(instance==null)
{
instance=new SingletonClass();
}
return instance;
}
private SingletonClass(){
}
}
第二種形式:餓漢式
//對第一行static的一些解釋
// java允許我們在一個類里面定義靜態類。比如內部類(nested class)。
//把nested class封閉起來的類叫外部類。
//在java中,我們不能用static修飾頂級類(top level class)。
//只有內部類可以為static。
public class Singleton{
//在自己內部定義自己的一個實例,只供內部調用
private static final Singleton instance = new Singleton();
private Singleton(){
//do something
}
//這里提供了一個供外部訪問本class的靜態方法,可以直接訪問
public static Singleton getInstance(){
return instance;
}
}
第三種形式: 雙重鎖的形式
public class Singleton{
private static Singleton instance=null;
private Singleton(){
//do something
}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
二、應用舉例
1. 單例模式舉例:
package com.solid.pattern;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* 單例模式
* @author solid
*
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
/**
* 獲取配置文件的值
* @param key
*/
public void getMessage(String key) {
Locale locale = new Locale(key);
ResourceBundle res = ResourceBundle.getBundle("res_zh_CN");
String message = res.getString(key);
System.out.println(message);
}
}
package com.solid.pattern;
/**
* 單例模式測試
* @author solid
*
*/
public class TestSingleton {
private static Singleton singleton;
public static void main(String[] args) {
singleton = Singleton.getInstance();
singleton.getMessage("title");
}
}
2. 多例模式舉例:
package com.solid.pattern;
/**
* 多例模式
* @author solid
*
*/
public class Multiton {
private static Multiton multi1 = new Multiton();
private static Multiton multi2 = new Multiton();
private Multiton() {}
public static Multiton getInstance(int key) {
if(key == 1) {
return multi1;
} else {
return multi2;
}
}
/**
* 獲取1—6之間的隨機數
*/
public void getValue() {
int value = (int)(Math.random()*6+1);
System.out.println(value);
}
}
package com.solid.pattern;
/**
* 多例模式測試
* @author solid
*
*/
public class TestMultiton {
private static Multiton multi1;
private static Multiton multi2;
public static void main(String[] args) {
multi1 = Multiton.getInstance(1);
multi2 = Multiton.getInstance(2);
multi1.getValue();
multi2.getValue();
}
}
單例和多例的詳細描述:
1. 什么是單例多例:
所謂單例就是所有的請求都用一個對象來處理,比如我們常用的service和dao層的對象通常都是單例的,而多例則指每個請求用一個新的對象來處理,比如action;
2. 如何產生單例多例:
在通用的SSH中,單例在spring中是默認的,如果要產生多例,則在配置文件的bean中添加scope="prototype";
3. 為什么用單例多例:
之所以用單例,是因為沒必要每個請求都新建一個對象,這樣子既浪費CPU又浪費內存;
之所以用多例,是為了防止並發問題;即一個請求改變了對象的狀態,此時對象又處理另一個請求,而之前請求對對象狀態的改變導致了對象對另一個請求做了錯誤的處理;
用單例和多例的標准只有一個:
當對象含有可改變的狀態時(更精確的說就是在實際應用中該狀態會改變),則多例,否則單例;
4. 何時用單例?何時用多例?
對於struts2來說,action必須用多例,因為action本身含有請求參數的值,即可改變的狀態;
而對於STRUTS1來說,action則可用單例,因為請求參數的值是放在actionForm中,而非action中的;
另外要說一下,並不是說service或dao一定是單例,標准同第3點所講的,就曾見過有的service中也包含了可改變的狀態,同時執行方法也依賴該狀態,但一樣用的單例,這樣就會出現隱藏的BUG,而並發的BUG通常很難重現和查找;