http://blog.csdn.net/happy_horse/article/details/51164262
http://blog.csdn.net/beyond0525/article/details/22794221/
http://blog.csdn.net/liguangzhenghi/article/details/8076361
單例模式保證了在程序中只有一個實例存在並且能全局的訪問到。(1.應用中某個實例對象需要頻繁的被訪問.2.應用中只允許存在一個實例)
實現單例模式有以下幾個關鍵點:
(1)其構造函數不對外開放,一般爲private;(構造函數私有化,使得客戶端不能通過new的形式手動構造單例類的對象。)
(2)通過一個靜態方法或者枚舉返回單例類對象;(單例類的實例一旦創建,便不會被系統回收,除非手動設置爲null。)
(3)確保單例類的對象有且只有一個,尤其要注意多線程的場景;
(4)確保單例類對象在反序列化時不會重新創建對象;
一、懶漢式(線程不安全)
//懶漢式單例類.在第一次調用的時候實例化自己
public class Singleton {
//私有的構造函數
private Singleton() {}
//私有的靜態變量
private static Singleton single=null;
//暴露的公有靜態方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
(2)懶漢式(線程安全)使用synchronized 關鍵字
public class Singleton {
//私有的靜態變量
private static Singleton instance;
//私有的構造方法
private Singleton (){};
//公有的同步靜態方法
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
每次調用getInstance()都進行同步,造成了不必要的同步開銷。這種模式一般不建議使用。在Android源碼中使用的該單例方法有:InputMethodManager,AccessibilityManager等都是使用這種單例模式
(3)餓漢模式(線程安全)
//餓漢式單例類.在類初始化時,已經自行實例化
public class Singleton {
//static修飾的靜態變量在內存中一旦創建,便永久存在
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
(4)DCL雙重校驗模式
public class Singleton {
private volatile static Singleton singleton; //靜態變量
private Singleton (){} //私有構造函數
public static Singleton getInstance() {
if (singleton == null) { //第一層校驗
synchronized (Singleton.class) {
if (singleton == null) { //第二層校驗
singleton = new Singleton();
}
}
}
return singleton;
}
}
對singleton 進行了兩次判斷是否空,第一層判斷是爲了避免不必要的同步,第二層的判斷是爲了在null的情況下才創建實例。存在嚴重安全隱患。
(5)靜態內部類單例模式
public class Singleton {
private Singleton (){} ;//私有的構造函數
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
//定義的靜態內部類
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton(); //創建實例的地方
}
}
當第一次加載Singleton 類的時候並不會初始化INSTANCE ,只有第一次調用Singleton 的getInstance()方法時纔會導致INSTANCE 被初始化。因此,第一次調用getInstance()方法會導致虛擬機加載SingletonHolder 類,這種方式不僅能夠確保單例對象的唯一性,同時也延遲了單例的實例化。
使用:SingletonInner.getInstance();
(6)枚舉單例
public enum Singleton { //enum枚舉類
INSTANCE;
public void whateverMethod() {
}
}
(7)使用容器實現單例模式
public class SingletonManager {
private static Map<String, Object> objMap = new HashMap<String,Object>();//使用HashMap作爲緩存容器
private Singleton() {
}
public static void registerService(String key, Objectinstance) {
if (!objMap.containsKey(key) ) {
objMap.put(key, instance) ;//第一次是存入Map
}
}
public static ObjectgetService(String key) {
return objMap.get(key) ;//返回與key相對應的對象
}
}
在程序的初始,將多種單例模式注入到一個統一的管理類中,在使用時根據key獲取對應類型的對象。
在Android源碼中,APP啓動的時候,虛擬機第一次加載該類時會註冊各種ServiceFetcher,比如LayoutInflater Service。將這些服務以鍵值對的形式存儲在一個HashMap中,用戶使用時只需要根據key來獲取到對應的ServiceFetcher,然後通過ServiceFetcher對象的getService函數獲取具體的服務對象。當第一次獲取時,會調用ServiceFetcher的creatService函數創建服務對象,然後將該對象緩存到一個列表中,下次再取時直接從緩存中獲取,避免重複創建對象,從而達到單例的效果。Android中的系統核心服務以單例形式存在,減少了資源消耗。
總結:不管以哪種形式實現單例模式,它們的核心原理是將構造函數私有化,並且通過靜態公有方法獲取一個唯一的實例,在這個獲取的過程中必須保證線程的安全,同時也要防止反序列化導致重新生成實例對象。
工廠方法模式
http://blog.csdn.net/self_study/article/details/51419770
任何需要生成複雜對象的地方,都可以使用工廠方法模式。工廠方法模式(Factory Method Pattern)定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,工廠方法讓類把實例化推遲到子類,這樣的設計將對象的創建封裝其來,以便於得到更松耦合,更有彈性的設計。降低了對象之間的耦合度,代碼結構清晰,對調用者隱藏了產品的生產過程,生產過程改變後,調用者不用做什麼改變,易於修改。易於拓展,要增加工廠和產品都非常方便,直接實現接口,不用修改之前的代碼。
Product(抽象產品角色):它是具體產品繼承的父類或者是實現的接口。在java中一般有抽象類或者接口來實現。
ConcreteProduct(具體產品角色):具體工廠角色所創建的對象就是此角色的實例。在java中由具體的類來實現。
Factory(抽象工廠角色):這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。
ConcreteFactory(具體工廠角色):它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。
模式1
1.抽象的產品:
public abstract class Product {
public abstract void method();
}
2.具體的產品:
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("產品A");
}
}
public class ConcreteProductB extends Product {
@Override
public void method() {
System.out.println("產品B");
}
}
3.抽象的工廠:
public abstract class Factory {
public abstract Product createProduct();
}
4.具體的工廠:
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
5.客戶端使用:
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct();
product.method();
}
}
這樣就生產出來一個ConcreteProductA。
模式2
通過反射來了解要生產哪個產品
1.抽象工廠:
public abstract class Factory {
public abstract <T extends Product> T createProduct(Class<T> clz);
}
2.具體工廠:
public class ConcreteFactory extends Factory {
@Override
public <T extends Product> T createProduct(Class<T> clz) {
Product product = null;
try {
product= (Product) Class.forName(clz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) product;
}
}
3.客戶端調用:
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct(ConcreteProductB.class);
product.method();
}
}
這樣,客戶端調用的時候,傳入什麼產品就生產什麼產品。
模式3
可以爲每個產品都創建一個具體的工廠類,如:
public class ConcreteFactoryA extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteFactoryB extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
要生產哪個就調用哪個工廠。這種叫多工廠方法模式。