1、單例模式:html
優勢:java
缺點:沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。數據庫
使用場景:編程
注意事項:getInstance() 方法中須要使用同步鎖 synchronized (Singleton.class) 防止多線程同時進入形成 instance 被屢次實例化。設計模式
1.餓漢式(線程安全,調用效率高,可是,不能延時加載)緩存
// 餓漢式單例 public class Singleton1 { // 指向本身實例的私有靜態引用,主動建立 private static Singleton1 singleton1 = new Singleton1(); // 私有的構造方法 private Singleton1(){} // 以本身實例爲返回值的靜態的公有方法,靜態工廠方法 public static Singleton1 getSingleton1(){ return singleton1; } }
咱們知道,類加載的方式是按需加載,且加載一次。。所以,在上述單例類被加載時,就會實例化一個對象並交給本身的引用,供系統使用;並且,因爲這個類在整個生命週期中只會被加載一次,所以只會建立一個實例,即可以充分保證單例。安全
優勢:這種寫法比較簡單,就是在類裝載的時候就完成實例化。避免了線程同步問題。多線程
缺點:在類裝載的時候就完成實例化,沒有達到Lazy Loading的效果。若是從始至終從未使用過這個實例,則會形成內存的浪費。併發
2.懶漢式(線程安全,調用效率低,可是,能夠延時加載)框架
// 懶漢式單例 public class Singleton2 { // 指向本身實例的私有靜態引用 private static Singleton2 singleton2; // 私有的構造方法 private Singleton2(){} // 以本身實例爲返回值的靜態的公有方法,靜態工廠方法 public static Singleton2 getSingleton2(){ // 被動建立,在真正須要使用時纔去建立 if (singleton2 == null) { singleton2 = new Singleton2(); } return singleton2; } }
咱們從懶漢式單例能夠看到,單例實例被延遲加載,即只有在真正使用的時候纔會實例化一個對象並交給本身的引用。
這種寫法起到了Lazy Loading的效果,可是隻能在單線程下使用。若是在多線程下,一個線程進入了if (singleton == null)判斷語句塊,還將來得及往下執行,另外一個線程也經過了這個判斷語句,這時便會產生多個實例。因此在多線程環境下不可以使用這種方式。
3.雙重檢測鎖式(因爲JVM底層內部模型緣由,偶爾會出現問題。不建議使用)
public class Singleton { private static Singleton instance; //程序運行時建立一個靜態只讀的進程輔助對象 private static readonly object syncRoot = new object(); private Singleton() { } public static Singleton GetInstance() { //先判斷是否存在,不存在再加鎖處理 if (instance == null) { //在同一個時刻加了鎖的那部分程序只有一個線程能夠進入 lock (syncRoot) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
Double-Check概念對於多線程開發者來講不會陌生,如代碼中所示,咱們進行了兩次if (singleton == null)檢查,這樣就能夠保證線程安全了。這樣,實例化代碼只用執行一次,後面再次訪問時,判斷if (singleton == null),直接return實例化對象。
使用雙重檢測同步延遲加載去建立單例的作法是一個很是優秀的作法,其不但保證了單例,並且切實提升了程序運行效率
優勢:線程安全;延遲加載;效率較高。
4.靜態內部類式(線程安全,調用效率高,能夠延時加載)
public sealed class Singleton{ private static class SingletonInstance{ //在第一次引用類的任何成員時建立實例,公共語言運行庫負責處理變量初始化 private static final Singleton instance=new Singleton(); } private Singleton() { } public static Singleton getInstance(){ return SingletonInstance.instance; } }
外部類沒有static屬性,則不會像餓漢式那樣當即加載對象。
只有真正調用getInstance(),纔會加載靜態內部類。加載類時是線程安全的。instance是static final類型,保證了內存中只有這樣一個實例存在,並且只能被賦值一次,從而保證了線程安全性。
兼備了併發高效調用和延遲加載的優點!
5.枚舉實現單例模式
public enum Singleton{ //定義一個枚舉元素,它就表明了Singleton的一個實例 INSTANCE; //單例能夠有本身的操做 public void singletonOperation(){ //功能處理(可額外添加須要的操做) } }
優勢:實現簡單
枚舉自己就是單例模式。因爲JVM根本上提供保障,避免經過反射和反序列化的漏洞
缺點:無延遲加載
2、工廠模式
實現了建立者和調用者的分離。
分類:簡單工廠模式、工廠方法模式、抽象工廠模式
面向對象設計的基本原則
OCP(開閉原則):一個軟件的實體應當對擴展開放,對修改關閉。
DIP(依賴倒轉原則):要針對接口編程,不要針對實現編程。
LOD(迪米特法則):只與你直接的朋友通訊,而避免和陌生人通訊。
工廠核心本質:
實例化對象,用工廠方法代替new操做,將選擇實現類、建立對象統一管理和控制,從而將調用者跟咱們的實現類解耦。
簡單工廠模式
咱們將建立一個 Shape 接口
public interface Shape { void draw(); }
實現 Shape 接口的實體類
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }
public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); }
public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }
建立一個工廠,生成基於給定信息的實體類的對象。
public class ShapeFactory { //使用 getShape 方法獲取形狀類型的對象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } }
使用該工廠,經過傳遞類型信息來獲取實體類的對象。
public class FactoryPatternDemo { public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); //獲取 Circle 的對象,並調用它的 draw 方法 Shape shape1 = shapeFactory.getShape("CIRCLE"); //調用 Circle 的 draw 方法 shape1.draw(); //獲取 Rectangle 的對象,並調用它的 draw 方法 Shape shape2 = shapeFactory.getShape("RECTANGLE"); //調用 Rectangle 的 draw 方法 shape2.draw(); //獲取 Square 的對象,並調用它的 draw 方法 Shape shape3 = shapeFactory.getShape("SQUARE"); //調用 Square 的 draw 方法 shape3.draw(); } }
執行程序,輸出結果:
Inside Circle::draw() method. Inside Rectangle::draw() method. Inside Square::draw() method.
2、工廠方法模式
public interface IFactory { ICar CreateCar(); }
建立抽象產品
public interface ICar { void GetCar(); }
建立具體工廠代碼:
// 具體工廠類: 用於建立跑車類 public class SportFactory : IFactory { public ICar CreateCar() { return new SportCar(); } } // 具體工廠類: 用於建立越野車類 public class JeepFactory : IFactory { public ICar CreateCar() { return new JeepCar(); } } // 具體工廠類: 用於建立兩廂車類 public class HatchbackFactory : IFactory { public ICar CreateCar() { return new HatchbackCar(); } }
建立具體產品代碼:
// 具體產品類: 跑車 public class SportCar : ICar { public void GetCar() { System.out.println("跑車"); } } // 具體產品類: 越野車 public class JeepCar : ICar { public void GetCar() { System.out.println("越野車"); } } // 具體產品類: 兩箱車 public class HatchbackCar : ICar { public void GetCar() { System.out.println("兩箱車"); } }
建立客戶端代碼:
class Client{ public static void main(string[] args){ ICar c1 = new SportFactory.CreateCar();
ICar c2 = new JeepFactory .CreateCar();
ICar c3 = new HatchbackFactory .CreateCar();
c1.GetCar();
c2.GetCar();
c3.GetCar(); } }
工廠方法的優勢/缺點:
代理模式: