欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設計模式筆記之Builder模式

 更新時間:2022年03月08日 10:54:49   作者:湫水長天  
建造者模式是日常開發(fā)中比較常見的設計模式,它的主要作用就是將復雜事物創(chuàng)建的過程抽象出來,該抽象的不同實現(xiàn)方式不同,創(chuàng)建出的對象也不同,這篇文章主要給大家介紹了關于Java設計模式筆記之Builder模式的相關資料,需要的朋友可以參考下

當我第一次使用Picasso的時候,看見下面的官網(wǎng)示例時,我和我的小伙伴都驚呆了!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

如此簡潔明了的使用方式,如此靈活多變的鏈式調(diào)用,讓我深深地迷住了,然后我一直苦苦追求它,奈何天資愚笨,不知如何掀起它的神秘面紗...

不好意思,中二病又犯了,重來一遍。經(jīng)過不懈的努力,終于發(fā)現(xiàn)它就是傳說中的Builder(建造者)模式,并學會了如何與它親密相處。

Builder模式是怎么來的

不知道是哪位賢人曾經(jīng)說過,存在即為合理。Builder模式在眾多的框架以及android原生代碼中存在(比如AlertDialog),就一定有其價值,用來解決某些需求。

考慮這樣一個場景,假如有一個類(****User****),里面有很多屬性,并且你希望這些類的屬性都是不可變的(final),就像下面的代碼:

public class User {
    private final String firstName;     // 必傳參數(shù)
    private final String lastName;      // 必傳參數(shù)
    private final int age;              // 可選參數(shù)
    private final String phone;         // 可選參數(shù)
    private final String address;       // 可選參數(shù)
}

在這個類中,有些參數(shù)是必要的,而有些參數(shù)是非必要的。就好比在注冊用戶時,用戶的姓和名是必填的,而年齡、手機號和家庭地址等是非必需的。那么問題就來了,如何創(chuàng)建這個類的對象呢?

一種可行的方案就是實用構(gòu)造方法。第一個構(gòu)造方法只包含兩個必需的參數(shù),第二個構(gòu)造方法中,增加一個可選參數(shù),第三個構(gòu)造方法中再增加一個可選參數(shù),依次類推,直到構(gòu)造方法中包含了所有的參數(shù)。

    public User(String firstName, String lastName) {
        this(firstName, lastName, 0);
    }

    public User(String firstName, String lastName, int age) {
        this(firstName, lastName, age, "");
    }

    public User(String firstName, String lastName, int age, String phone) {
        this(firstName, lastName, age, phone, "");
    }

    public User(String firstName, String lastName, int age, String phone, String address) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }

這樣做的好處只有一個:可以成功運行。但是弊端很明顯:

  • 參數(shù)較少的時候問題還不大,一旦參數(shù)多了,代碼可讀性就很差,并且難以維護。
  • 對調(diào)用者來說也很麻煩。如果我只想多傳一個address參數(shù),還必需給age、phone設置默認值。而且調(diào)用者還會有這樣的困惑:我怎么知道第四個String類型的參數(shù)該傳address還是phone?

第二種解決辦法就出現(xiàn)了,我們同樣可以根據(jù)JavaBean的習慣,設置一個空參數(shù)的構(gòu)造方法,然后為每一個屬性設置setters和getters方法。就像下面一樣:

public class User {
    private String firstName;     // 必傳參數(shù)
    private String lastName;      // 必傳參數(shù)
    private int age;              // 可選參數(shù)
    private String phone;         // 可選參數(shù)
    private String address;       // 可選參數(shù)

    public User() {
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }
}

這種方法看起來可讀性不錯,而且易于維護。作為調(diào)用者,創(chuàng)建一個空的對象,然后只需傳入我感興趣的參數(shù)。那么缺點呢?也有兩點:

  • 對象會產(chǎn)生不一致的狀態(tài)。當你想要傳入5個參數(shù)的時候,你必需將所有的setXX方法調(diào)用完成之后才行。然而一部分的調(diào)用者看到了這個對象后,以為這個對象已經(jīng)創(chuàng)建完畢,就直接食用了,其實User對象并沒有創(chuàng)建完成。
  • ****User****類是可變的了,不可變類所有好處都不復存在。

終于輪到主角上場的時候了,利用Builder模式,我們可以解決上面的問題,代碼如下:

public class User {
    private final String firstName;     // 必傳參數(shù)
    private final String lastName;      // 必傳參數(shù)
    private final int age;              // 可選參數(shù)
    private final String phone;         // 可選參數(shù)
    private final String address;       // 可選參數(shù)

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }

    public static class UserBuilder {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;

        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }

        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}

有幾個重要的地方需要強調(diào)一下:

  • ****User****類的構(gòu)造方法是私有的。也就是說調(diào)用者不能直接創(chuàng)建User對象。
  • ****User****類的屬性都是不可變的。所有的屬性都添加了final修飾符,并且在構(gòu)造方法中設置了值。并且,對外只提供getters方法。
  • Builder模式使用了鏈式調(diào)用??勺x性更佳。
  • Builder的內(nèi)部類構(gòu)造方法中只接收必傳的參數(shù),并且該必傳的參數(shù)適用了final修飾符。

相比于前面兩種方法,Builder模式擁有其所有的優(yōu)點,而沒有上述方法中的缺點??蛻舳说拇a更容易寫,并且更重要的是,可讀性非常好。唯一可能存在的問題就是會產(chǎn)生多余的Builder對象,消耗內(nèi)存。然而大多數(shù)情況下我們的Builder內(nèi)部類使用的是靜態(tài)修飾的(static),所以這個問題也沒多大關系。

現(xiàn)在,讓我們看看如何創(chuàng)建一個User對象呢?

new User.UserBuilder("王", "小二")
                .age(20)
                .phone("123456789")
                .address("亞特蘭蒂斯大陸")
                .build();

相當整潔,不是嗎?你甚至可以用一行代碼完成對象的創(chuàng)建。

關于Builder的一點說明

線程安全問題

由于Builder是非線程安全的,所以如果要在Builder內(nèi)部類中檢查一個參數(shù)的合法性,必需要在對象創(chuàng)建完成之后再檢查。

public User build() {
  User user = new user(this);
  if (user.getAge() > 120) {
    throw new IllegalStateException(“Age out of range”); // 線程安全
  }
  return user;
}

上面的寫法是正確的,而下面的代碼是非線程安全的:

public User build() {
  if (age > 120) {
    throw new IllegalStateException(“Age out of range”); // 非線程安全
  }
  return new User(this);
}

經(jīng)典的Builder模式

上面介紹的Builder模式當然不是“原生態(tài)”的啦,經(jīng)典的Builder模式的類圖如下:

builder

其中:

  • Product 產(chǎn)品抽象類。
  • Builder 抽象的Builder類。
  • ConcretBuilder 具體的Builder類。
  • Director 同一組裝過程。

當然,之前實例中的Builder模式,是省略掉了Director的,這樣結(jié)構(gòu)更加簡單。所以在很多框架源碼中,涉及到Builder模式時,大多都不是經(jīng)典GOF的Builder模式,而是省略后的。

總結(jié)

到此這篇關于Java設計模式筆記之Builder模式的文章就介紹到這了,更多相關Java設計模式Builder模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring注解驅(qū)動之ApplicationListener用法解讀

    Spring注解驅(qū)動之ApplicationListener用法解讀

    這篇文章主要介紹了Spring注解驅(qū)動之ApplicationListener用法解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 詳解Spring Aop實例之xml配置

    詳解Spring Aop實例之xml配置

    本篇文章主要介紹了詳解Spring Aop實例之xml配置,使用xml可以對aop進行集中配置,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java8之lambda表達式基本語法

    Java8之lambda表達式基本語法

    本文通過示例大家給大家介紹了java8之lambda表達式的基本語法,感興趣的的朋友一起看看吧
    2017-08-08
  • springboot整合druid連接池的步驟

    springboot整合druid連接池的步驟

    這篇文章主要介紹了springboot整合druid連接池的步驟,幫助大家更好的理解和學習springboot框架,感興趣的朋友可以了解下
    2020-11-11
  • java網(wǎng)絡之基于UDP的聊天程序示例解析

    java網(wǎng)絡之基于UDP的聊天程序示例解析

    這篇文章主要介紹了java網(wǎng)絡之基于UDP的聊天程序示例解析,文中通過步驟及示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • 5分鐘快速創(chuàng)建spring boot項目的完整步驟

    5分鐘快速創(chuàng)建spring boot項目的完整步驟

    這篇文章主要給大家介紹了關于通過5分鐘快速創(chuàng)建spring boot項目的完整步驟,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06
  • Java多線程及分布式爬蟲架構(gòu)原理解析

    Java多線程及分布式爬蟲架構(gòu)原理解析

    這篇文章主要介紹了Java多線程及分布式爬蟲架構(gòu)原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Spring Boot 打包與熱部署的操作方法

    Spring Boot 打包與熱部署的操作方法

    這篇文章主要介紹了Spring Boot 打包與熱部署的操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Spring AOP 自定義注解的實現(xiàn)代碼

    Spring AOP 自定義注解的實現(xiàn)代碼

    本篇文章主要介紹了Spring AOP 自定義注解的實現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • SpringBoot使用JTA實現(xiàn)對多數(shù)據(jù)源的事務管理

    SpringBoot使用JTA實現(xiàn)對多數(shù)據(jù)源的事務管理

    了解事務的都知道,在我們?nèi)粘i_發(fā)中單單靠事務管理就可以解決絕大多數(shù)問題了,但是為啥還要提出JTA這個玩意呢,到底JTA是什么呢?他又是具體來解決啥問題的呢?本文小編就給大家介紹一下如何在Spring Boot中使用JTA實現(xiàn)對多數(shù)據(jù)源的事務管理
    2023-11-11

最新評論