設計模式之建造者模式

image.png

這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰java

歡迎來到今天的學習,今天咱們一塊兒來嘮嘮建造者模式。多嘮叨幾句,前面我有提到本月將會對java的設計模式精講,歡迎點擊頭像,關注個人專欄,我會持續更新,加油!算法

系列文章:編程

設計模式之單例模式設計模式

設計模式之工廠模式markdown

....系列持續更新框架

話很少話,進入正題ide

建造者模式

建造者模式是另一個高頻使用的建立型設計模式——一般叫 Builder 模式,中文通常叫建造者模式或生成器模式。函數

今天咱們改變下策略,先開始不講原理,先從例子下手,從解決問題案例當中去尋求答案。你認爲的那種答案。oop

先看建造者模式主要帶來什麼或者解決什麼問題:post

  • 直接使用構造函數或者使用 set 方法來建立對象方不方便?,有沒有一種簡單的方法建立對象

  • 存在的價值,爲何須要建造者模式建立對象

下面經過代碼具體深刻理解,咱們只講乾貨,讓你看完就能解決如今你代碼中的實際問題!

場景及案例分享

對同一種場景咱們用建造者模式和不用建造者模式來進行代碼對比:

很簡單,咱們建立學生對象

/** * 學生實體 * 不用建造者模式 */
public class Students {
    private String name;    //姓名
    private int age;        //年齡
    private String grade;   //班級
    private String gender;  //性別
    public Student(String name, int age, String grade, String gender) {
        this.name = name;
        this.age = age;
        this.grade = grade;
        this.gender = gender;
    }
    public Student(String name, int age, String grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
   
}

 //上述代碼寫了三個不一樣參數的構造函數
public static void main(String[] args) {
    Student student01 = new Student("張三",26,"13班","男");
    
    Student student02 = new Student("張三",26,"13班");
    
    ...
}
複製代碼

上述有問題嗎,沒有問題。這代碼能夠嗎,你以爲呢?問題顯而易見(確定還有不少小夥伴日常工做中都是這麼搞的)。上面這段代碼沒有使用建造者模式,因此咱們須要使用傳統的 getter、setter 方法,並指定不一樣的入參來構造對象。若是參數過多,業務比較多,那須要建立太多構造方法。

而使用建造者模式後的類,功能卻發生了徹底不同的變化,以下所示:

/** * 學生實體 * * 使用建造者模式建立對象 */
public class Students {
    //全部屬性
    private String name;   
    private int age;       
    private String grade;  
    private String gender; 
    
    public Students() {
    }
    
    //內部builder new對象
    public static Students builder() {
        return new Students();
    }
    
    //將屬性做爲步驟
    public Students name(String name) {
        this.name = name;
        return this;
    }
    //將屬性做爲步驟
    public Students age(int age) {
        this.age = age;
        return this;
    }
    //將屬性做爲步驟
    public Students grade(String grade) {
        this.grade = grade;
        return this;
    }
    //將屬性做爲步驟
    public Students gender(String gender) {
        this.gender = gender;
        return this;
    }
    
    //執行建立操做(最後封口return)
    public Students build() {
        validateObject(this);
        return this;
    }
    private void validateObject(Students Students) {
        //能夠作基礎預校驗,或自定義校驗
    }
    @Override
    public String toString() {
        return "Students{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", grade='" + grade + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
}



 //用建造者模式來建立對象
public static void main(String[] args) {
    
    //建立對象
    Students st = Students.builder()
            .name("張三")
            .age("26")
            .grade("13班")
            .gender("男")
            .build();
            
      //建立對象
    Students st01 = Students.builder()
            .name("張三")
            .age("26")
            .grade("13班")
            .build();       
            
     //一步步建造一個個屬性 
}

複製代碼

這,就是建造者模式來搞定對象。咱們能夠發現構建出了徹底不一樣的對象實例,而使用傳統的 getter、setter 方法,則須要寫不少不一樣的構造函數來應對變化。

因此說,使用建造者模式能更方便地幫助咱們按需進行對象的實例化,避免寫不少不一樣參數的構造函數,同時還能解決同一類型參數只能寫一個構造函數的弊端。

雖然上面案例的實現比較簡單,可是也充分演示瞭如何使用建造者模式。在實際的使用中,一般能夠直接使用 lombok 的 @Builder 註解實現類自身的建造者模式

爲何使用建造者模式來建立對象?存在的意義是什麼

爲何要使用建造者模式來建立類?在我看來,有如下幾點緣由。

  • 第一,分步驟的屬性賦值更適合屢次運算結果類建立場景。在面向對象軟件開發中,不少時候建立類所須要的參數並非一次都能準備好的,好比,計算訂單優惠價格、查詢庫存狀態等,有的參數可能須要經過調用多個服務運算後才能得出,這時咱們能夠根據已知參數預先對類進行建立,等有合適的參數時再設置類的屬性,而不是等到全部結果都齊備後纔去建立類。

  • 第二,不須要關心特定類型的建造者的具體算法實現。 好比,咱們在使用 StringBuilder 時,並不太關心它的具體代碼實現,而是關心它提供給咱們的使用功能。這在某些須要快速複用的場景中,能起到提高編碼效率的做用。

  • 第三,提升代碼的可閱讀性,簡潔明瞭,須要哪一個功能(屬性),就調用哪一個,方便閱讀,可維護性強。內部屬性擴展性極強,自由地組合對象屬性

  • 第四知足開閉原則,這也是設計模式的優勢。 每個建造者都相對獨立,所以能方便地進行替換或新增,這就大大提高了代碼的可擴展性。

固然,誇獎完,仍是要指出一些存在一些客觀性存在的問題。

  • 使用範圍有限。 建造者模式所建立的對象通常都須要有不少的共同點,若是對象實例之間的差別性很大,則不適合使用建造者模式。

  • 容易形成超類,業務繁多,新的建立步驟就會被加進來,這會形成代碼量的急劇膨脹,類會變得臃腫,最終造成一個龐大的超大類。

Netty當中的建造者模式

咱們來看下Netty框架當中是怎麼運用建造者模式的(Netty不懂的自行百度下,後續我會對Netty做出專題來說)。

你們還記得,在服務端啓動的時候有個啓動輔助類ServerBootStrap,咱們調用group方法、channel方法設置參數。這裏面也使用了這種建造者鏈式編程來設置相關參數。

ServerBootstrap b = new ServerBootstrap();
//開始建立對象
b.group(bossGroup, workerGroup) //bossGroup和workerGroup 先不用管,本節主要講建造者模式

            //賦值channel參數
            .channel(NioServerSocketChannel.class)
            //賦值option參數
            .option(ChannelOption.SO_BACKLOG, 100)
            //賦值handler參數
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    System.out.println("服務啓動");
                }
            });
    
複製代碼

下面咱們來一塊兒看下源碼,源碼我就直接從idea當中截圖了,我會從中圈出重點:

先看group,設置完參數以後,便返回this對象

image.png

再看 childHandler,依然如此,是否是和咱們上面學生的例子是同樣的

image.png

其餘幾個參數也是同樣,你們能夠自行看下。

總結

OK,今天咱們的建造者模式就講到這裏,感謝你的閱讀,相信你能從中學到東西。同時也很是歡迎您的點贊,關注和分享!

我已經將本章收錄在專題裏,點擊文章下方專題,關注專欄,我會天天發表乾貨,本月我會持續輸入設計模式。咱們下期再見!

相關文章
相關標籤/搜索