經常使用的設計模式

1、單例模式:html

  • 一、單例類只能有一個實例。
  • 二、單例類必須本身建立本身的惟一實例。
  • 三、單例類必須給全部其餘對象提供這一實例。

優勢:java

  • 一、在內存裏只有一個實例,減小了內存的開銷,尤爲是頻繁的建立和銷燬實例(好比管理學院首頁頁面緩存)。
  • 二、避免對資源的多重佔用(好比寫文件操做)。

缺點:沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。數據庫

使用場景:編程

  • 一、要求生產惟一序列號。
  • 二、WEB 中的計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。
  • 三、建立的一個對象須要消耗的資源過多,好比 I/O 與數據庫的鏈接等。

注意事項: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操做,將選擇實現類、建立對象統一管理和控制,從而將調用者跟咱們的實現類解耦。

 

簡單工廠模式

簡單工廠模式是屬於建立型模式,又叫作靜態工廠方法模式,但不屬於23種GOF設計模式之一。簡單工廠模式是由一個工廠對象決定建立出哪種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,能夠理解爲是不一樣工廠模式的一個特殊實現。

咱們將建立一個 Shape 接口

 public interface Shape { void draw(); } 

實現 Shape 接口的實體類

Rectangle.java

public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Square.java

public class Square implements Shape {
 
    @Override
    public void draw() {
      System.out.println("Inside Square::draw() method.");
  
 }

Circle.java

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、工廠方法模式
工廠方法模式Factory Method,又稱多態性工廠模式。在工廠方法模式中,核心的工廠類再也不負責全部的產品的建立,而是將具體建立的工做交給子類去作。該核心類成爲一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪個產品類應當被實例化這種細節。
工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。首先徹底實現‘開-閉 原則’,實現了可擴展。其次更復雜的層次結構,能夠應用於產品結果複雜的場合。
 
建立抽象工廠:
   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();
        }
    }

工廠方法的優勢/缺點: 

  • 優勢:
    • 子類提供掛鉤。基類爲工廠方法提供缺省實現,子類能夠重寫新的實現,也能夠繼承父類的實現。-- 加一層間接性,增長了靈活性
    • 屏蔽產品類。產品類的實現如何變化,調用者都不須要關心,只需關心產品的接口,只要接口保持不變,系統中的上層模塊就不會發生變化。
    • 典型的解耦框架。高層模塊只須要知道產品的抽象類,其餘的實現類都不須要關心,符合迪米特法則,符合依賴倒置原則,符合里氏替換原則。
    • 多態性:客戶代碼能夠作到與特定應用無關,適用於任何實體類。
  • 缺點:須要Creator和相應的子類做爲factory method的載體,若是應用模型確實須要creator和子類存在,則很好;不然的話,須要增長一個類層次。(不過說這個缺點好像有點吹毛求疵了)

 代理模式:

 http://www.javashuo.com/article/p-vbeoztly-dd.html

相關文章
相關標籤/搜索