單例模式與工廠方法模式

    單例模式
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();
    }
}
要生產哪個就調用哪個工廠。這種叫多工廠方法模式。

















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章