国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

java與es8實戰(zhàn)之一:以builder pattern開篇

這篇具有很好參考價值的文章主要介紹了java與es8實戰(zhàn)之一:以builder pattern開篇。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

歡迎訪問我的GitHub

這里分類和匯總了欣宸的全部原創(chuàng)(含配套源碼):https://github.com/zq2599/blog_demos

關于《java與es8實戰(zhàn)》系列

  • 《java與es8實戰(zhàn)》系列是欣宸與2022年夏季推出的原創(chuàng)系列,如標題所述,該系列從一個java程序員視角去學習和實踐elasticsearch的8.2版本,目標是與大家一起掌握與elasticsearch開發(fā)相關的技能,以應對實際應用中的需求和挑戰(zhàn)

本篇概覽

  • 縱觀欣宸過往各種系列文章,開篇無外乎兩種套路
  1. 第一種是對該系列的主題做重點介紹,把重點、背景說清楚
  2. 第二種更加實在,就是準備工作,例如安裝相關的軟件,介紹對應版本,甚至寫個初級的hello world
  • 那么《java與es8實戰(zhàn)》系列的開篇應該是哪種風格?是介紹elasticsearch?還是動手部署一套es集群?亦或是用java寫一套簡單的增刪改查代碼,讓大家可以快速入門?
  • 這個問題難住我了,思考良久,想到剛開始寫es代碼時的困惑,那時去看es的java庫源碼中的單元測試部分,研究如何調(diào)用java庫的api,看到那里是這么寫代碼的,先是創(chuàng)建索引,創(chuàng)建請求對象會用到builder
java與es8實戰(zhàn)之一:以builder pattern開篇
  • 再隨意逛到了批量操作的代碼,如下圖,還是builder
java與es8實戰(zhàn)之一:以builder pattern開篇
  • 最常用的聚合查詢,如下圖,也離不開builder
java與es8實戰(zhàn)之一:以builder pattern開篇
  • 于是我就納悶了:以后寫es相關的代碼,這builder操作難道會一直伴隨我?
  • 去翻閱es的官方文檔,發(fā)現(xiàn)說的很清楚:Java客戶端中的數(shù)據(jù)對象都是不可變的,這些數(shù)據(jù)對象在創(chuàng)建時用的是2008版本《Effective Java》中的builder模式
java與es8實戰(zhàn)之一:以builder pattern開篇
  • 回憶了這么多,我終于想清楚《java與es8實戰(zhàn)》的開篇內(nèi)容了:咱們不急著部署ES,也不急著寫增刪改查的入門級代碼,今天,欣宸邀您一同去溫習經(jīng)典,搞清楚以下問題:
  1. 直接用構造方法創(chuàng)建對象有什么問題?
  2. 用靜態(tài)方法創(chuàng)建對象有什么問題?
  3. builder模式是什么?
  4. builder模式解決了什么問題?
  5. builder模式自己有啥問題?
  6. es API和builder有啥關系?
  • 等咱們搞清楚這些問題,寫代碼操作es時遇到builder就不再疑惑,而是感受到builder帶來的好處,進而養(yǎng)成習慣,在今后設計不可變類時自然而然的用上builder模式,那時候您不一定還在用es,然而builder模式可以長久陪伴您,因為,經(jīng)典就是經(jīng)典,如下圖
java與es8實戰(zhàn)之一:以builder pattern開篇
  • 現(xiàn)在,咱們java程序員的es8開發(fā)之旅,就從經(jīng)典的builder pattern出發(fā)

不可變對象(Immutable Objects)

  • es的API中的對象都是不可變的(immutable),關于不可變,簡單的說就是:實例一旦創(chuàng)建后,不能改變其成員變量的值
  • 本篇文章討論的創(chuàng)建對象,都是指的不可變對象

三種創(chuàng)建對象的常用方法

  • 這三種分別是
  1. 構造方法
  2. 靜態(tài)工廠方法
  3. builder模式

直接用構造方法創(chuàng)建對象有什么問題

  • 創(chuàng)建一個對象,最常用的方法不就是構造方法么?new Object()不香嗎?

  • 成員變量很多的時候,構造方法就沒那么香了,舉例如下,NutritionFacts是食品包裝外面顯示的營養(yǎng)成分標簽,這里面有的營養(yǎng)成分是必須的:每一份的含量、每一罐的含量,其他的可選

public class NutritionFacts {
    private final int servingSize;  // (mL)            required
    private final int servings;     // (per container) required
    private final int calories;     //                 optional
    private final int fat;          // (g)             optional
    private final int sodium;       // (mg)            optional
    private final int carbohydrate; // (g)             optional

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories) {
        this(servingSize, servings, calories, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat) {
        this(servingSize, servings, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public NutritionFacts(int servingSize, int servings,
           int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize  = servingSize;
        this.servings     = servings;
        this.calories     = calories;
        this.fat          = fat;
        this.sodium       = sodium;
        this.carbohydrate = carbohydrate;
    }
}
  • 從上面的代碼可見,為了盡量滿足用戶需要,NutritionFacts提供了多個構造方法給用戶使用,其實相信您也明白這里面的問題:這簡直是成員變量的各種排列組合呀,以后要是加字段就麻煩了
  • 再以一個使用者的視角來看看,實例化代碼如下,這就有點暈了,這一眼看過去,誰知道240給了哪個字段?只能去核對構造方法的入?yún)⒙暶?/li>
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
  • 緩解上述問題的一種方法是使用JavaBeans模式,用無參構造方法,然后按照調(diào)用setXXX設置每個所需字段,示例如下所示
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
  • 上述方法似乎不錯,哪些字段被設置一目了然,所以,成員變量多的時候,用上述方法是正確選擇嗎?
  • 然而,《Effective Java》原著對上述做法的評價是有著嚴重的弊端(the JavaBeans pattern has serious disadvantages of its own),所以,盡早放棄吧...咱們來看看具體有啥問題
  1. 首先,直觀的看,這種做法違背了不可變對象的定義,創(chuàng)建出對象后,又用setXXX方法改變了成員變量
  2. 《Effective Java》的原話是在構造過程中JavaBean可能處于不一致的中的狀態(tài),我的理解如下圖所示,不用顏色代表不同線程,可以看到,紅色線程獲取calories的值的時候,藍色線程還沒有開始設置calories的值,所以紅色線程拿到的等于初始值0,這顯然是不對的,正常邏輯應該是:只要cocaCola對象非空,其calories字段對外顯示的值就是100
java與es8實戰(zhàn)之一:以builder pattern開篇
  1. 經(jīng)驗豐富的您應該想到了這是典型的線程同步問題,應該用synchronize或ReentrantLock給藍色代碼段加鎖,讓紅色代碼先block住,直到藍色代碼執(zhí)行完畢,這樣就能拿到正確的值了---這種方法顯然可以解決問題,然而《Effective Java》預判了您的預判:這種方式十分笨拙,在實踐中很少使用,想想也是,創(chuàng)建和使用對象是最常見的編碼了,這個思路要加多少synchronize或ReentrantLock
  • 所以構造方法不能滿足我們的實際需要,再來看看靜態(tài)工廠方法,它的優(yōu)勢在哪里

靜態(tài)工廠方法的優(yōu)勢

  • 相比靜態(tài)工廠方法,構造方法存在以下五個典型問題
  1. 隨著入?yún)⒌牟煌?,構造方法可以有多個,如下所示,然而都是同名的,這會給用戶造成困惑,此刻用靜態(tài)工廠方法,可以自由設置方法名(例如createWithName或者createWithAge),讓用戶更方便的選擇合適的方法
    public Student(String name) {
        this.name = name;
    }

    public Student(int age) {
        this.age = age;
    }
  1. 使用構造方法意味著創(chuàng)建對象,而有時候我們只想使用,并不在乎對象本身是否是新建的,下面是Boolean.valueOf方法的源碼,此處并未新建Boolean對象:
    public static Boolean valueOf(String s) {
        return parseBoolean(s) ? TRUE : FALSE;
    }
  1. 以動物類Animal.class為例,Animal類的構造方法創(chuàng)建的對象Animal的實例,而靜態(tài)工廠方法的返回值聲明雖然是Animal,但實際返回的實例可以是Animal的子類,例如Dog
  2. 靜態(tài)工廠方法內(nèi)部可以有靈活的邏輯來決定返回那種子類的實例,來看的靜態(tài)工廠方法源碼,根據(jù)底層枚舉類型的大小來決定是返回RegularEnumSet實例還是JumboEnumSet實例
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }
  1. 靜態(tài)工廠方法還有一個優(yōu)勢:方法返回對象所屬的類,在編寫此靜態(tài)方法時可以不存在,這句話有點晦澀,可以回想一下JDBC的獲取connection的API,在編寫此API的時候,并不需要知道MySQL的driver實現(xiàn)
  • 以上的比較暴露出構造方法的缺陷,此時靜態(tài)工廠方法更加合適,然而,靜態(tài)工廠方法就這么完美嗎?

靜態(tài)工廠方法的不足

  • 只有最合適的,沒有最好的,靜態(tài)工廠方法也有自己的不足
  1. 當您開發(fā)一個類時,如果決定對外提供靜態(tài)工廠方法,那么將構造方法設為私有,就可以讓用戶只能選擇靜態(tài)工廠方法了,代碼如下所示,然而,這樣的Student類就無法被繼承
public class Student {
    private String name;

    private int age;

    public void setName(String name) {
        this.name = name;
    }

    private Student() {

    }

    public static Student newInstance(String name) {
        Student student = new Student();
        student.setName(name);

        return student;
    }
}
  1. 一個類的代碼中,可能已有一些靜態(tài)方法,再加入靜態(tài)工廠方法,一堆靜態(tài)方法混雜在一起,用戶從中找出靜態(tài)工廠方法怕是不容易

builder pattern

  • 看過了構造方法和靜態(tài)工廠方法,認識到它們的不足,終于該第三種方法登場了
  • builder pattern,《Effective Java》中文版譯作建造者模式,用builder對象來創(chuàng)建真正的對象實例,前面提到的構造方法和靜態(tài)工廠的不足,在builder pattern這里都得到了改善
  • 來看代碼吧,以剛才的NutritionFacts為例,使用builder pattern后的代碼如下,新增一個靜態(tài)成員類Builder,可以設置Builder的每個成員變量,最后調(diào)用其build方法的時候,才真正創(chuàng)建NutritionFacts對象
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories      = 0;
        private int fat           = 0;
        private int carbohydrate  = 0;
        private int sodium        = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

        public Builder calories(int val)
            { calories = val;      return this; }
        public Builder fat(int val)
            { fat = val;           return this; }
        public Builder carbohydrate(int val)
            { carbohydrate = val;  return this; }
        public Builder sodium(int val)
            { sodium = val;        return this; }

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

    private NutritionFacts(Builder builder) {
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}
  • 以一個使用者的視角來看如何創(chuàng)建NutritionFacts對象,如下所示,流暢的寫法,那些字段被設置以及具體的值都一目了然,最終build方法才會創(chuàng)建NutritionFacts對象,而且這是個不可變對象
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                              .calories(100)
                              .sodium(35)
                              .carbohydrate(27)
                              .build();

builder pattern自身的問題和適用場景

  • 即便能解決構造方法和靜態(tài)工廠自身的一些問題,builder pattern也不是萬能的,缺點很明顯:創(chuàng)建對象之前,先要創(chuàng)建builder對象,這在一些性能要求高、資源限制苛刻的場景中就不適合了
  • 另外builder pattern適合的場景是成員變量多的時候,而這個所謂的究竟如何理解呢?這可能是個小馬過河的問題吧:見慣了幾十個成員變量的類,再去看十幾個成員變量的類,可能會有種很清爽的感覺,呃,扯遠了,其實《Effective Java》的說法是四個或者更多個參數(shù),就適合用builder apttern了

elasticsearch API中的builder

  • 終于到達重點了:接下來的es之旅,會遇到什么樣的builder?咱們該怎么用它?
  • 先總結(jié)builder的使用套路,其實在es中的builder也是按照套路去用的,如下圖,其實很簡單,三步走而已,暫時把下圖稱為套路圖,后面還會提到
java與es8實戰(zhàn)之一:以builder pattern開篇
  • 看看es API的用法,以es自己的單元測試代碼為例,如下圖所示,創(chuàng)建一個索引時,會指向紅色箭頭所指的create方法

java與es8實戰(zhàn)之一:以builder pattern開篇

  • 來看看create的源碼,入?yún)⑹莻€Function,里面執(zhí)行了function的apply,這是個典型的lambda表達式作為入?yún)?/li>
	public final CreateIndexResponse create(Function<CreateIndexRequest.Builder, ObjectBuilder<CreateIndexRequest>> fn)
			throws IOException, ElasticsearchException {
		return create(fn.apply(new CreateIndexRequest.Builder()).build());
	}
  • Function的兩個泛型,第一個表示入?yún)?,第二個表示返回,對于create方法的用戶來說,這就有意思了:
  1. 咱們在寫這個lambda表達式時,入?yún)⑹莃uilder對象,這可以從上面的代碼中看到(即apply方法的入?yún)ⅲ?,也就是說套路圖中的第一步:創(chuàng)建builder對象,已經(jīng)被create方法內(nèi)部做好了
  2. 再看看上面的截圖中,lambda表達式做了什么? b.index("my-index"),這里可以按照實際業(yè)務需要調(diào)用builder的多個方法來來設置參數(shù),所以套路圖中的第二步,需要咱們在lambda表達式中完成,這很合理:需要設置哪些參數(shù)只有用戶最清楚
  3. 最后,也是最巧妙的地方,就是上面的create方法源碼中的.build(),因為fn.apply方法的實現(xiàn)是調(diào)用者寫的,例如剛才寫的是 b.index("my-index"),這個index方法的返回值就是build實例,所以fn.apply(xxx).build()就是套路圖中的第三步:builder的build方法被執(zhí)行了,真正的對象,即CreateIndexRequest對象此刻被創(chuàng)建,這也被es內(nèi)部給做好了
  • 小結(jié)如下圖
    java與es8實戰(zhàn)之一:以builder pattern開篇
  • 看到這里,不知您是否會擊掌叫好,builder與lambda的巧妙結(jié)合,整個套路中,第二步留給使用者按需定制,而固定的第一和第三步都被es自己實現(xiàn),對使用者來說顯得非常精簡,而整個過程并無特殊之處,都是對經(jīng)典的嫻熟應用
  • 經(jīng)歷了本文,今后在寫es操作代碼時,面對各種builder和lambda,相信您不再迷茫,取而代之的是模式的欣賞和品味,以及本就該如此的感悟
  • 網(wǎng)絡上寫es開發(fā)的系列文章并不少,像欣宸這樣拿builder做開篇的,應該獨一無二了...吧
  • 好了,《java與es8實踐》的畫卷已順利展開一角,接下來,請允許欣宸原創(chuàng)繼續(xù)陪伴您,像今天這樣踏踏實實,一步一個腳印,從入門到精通

歡迎關注博客園:程序員欣宸

學習路上,你不孤單,欣宸原創(chuàng)一路相伴...文章來源地址http://www.zghlxwxcb.cn/news/detail-665611.html

到了這里,關于java與es8實戰(zhàn)之一:以builder pattern開篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • java與es8實戰(zhàn)之三:Java API Client有關的知識點串講

    java與es8實戰(zhàn)之三:Java API Client有關的知識點串講

    這里分類和匯總了欣宸的全部原創(chuàng)(含配套源碼):https://github.com/zq2599/blog_demos 本篇是《java與es8實戰(zhàn)》系列的第三篇,將一些重要的知識點在這里梳理清楚,為后面的實踐奠定基礎 一共有七個與Java API Client有關的重要知識點 關于namespace:每個feature都有自己的package 命名規(guī)則:

    2024年02月11日
    瀏覽(48)
  • Java設計模式之建造者模式詳解(Builder Pattern)

    在日常的開發(fā)工作中,我們常常需要創(chuàng)建一些復雜的對象。這些對象可能包含許多不同的屬性,并且這些屬性的初始化過程可能相當復雜。在這種情況下,建造者模式是一種非常有用的設計模式,因為它允許我們分步驟地創(chuàng)建復雜的對象。 概念和原理: 建造者模式(Builder

    2024年02月09日
    瀏覽(25)
  • ES8 向量搜索(knn-search)java-api 實踐

    ES8 向量搜索(knn-search)java-api 實踐

    官方文檔-knn-search kNN搜索 k-nearest neighbor (kNN)搜索找到與查詢向量最近的k個向量,如通過相似度計算。 kNN的常見用例包括: 基于自然語言處理(NLP)算法的相關性排序 產(chǎn)品推薦和推薦引擎 圖像或視頻的相似性搜索 要運行kNN搜索,您必須能夠?qū)?shù)據(jù)轉(zhuǎn)換為有意義的向量值

    2024年02月12日
    瀏覽(21)
  • 最新版ES8的client API操作 Elasticsearch Java API client 8.0

    最新版ES8的client API操作 Elasticsearch Java API client 8.0

    作者:ChenZhen 本人不常看網(wǎng)站消息,有問題通過下面的方式聯(lián)系: 郵箱:1583296383@qq.com vx: ChenZhen_7 我的個人博客地址:https://www.chenzhen.space/?? 版權:本文為博主的原創(chuàng)文章,本文版權歸作者所有,轉(zhuǎn)載請附上原文出處鏈接及本聲明。?? 如果對你有幫助,請給一個小小的s

    2024年02月04日
    瀏覽(29)
  • 建造者模式(Builder Pattern)

    建造者模式(Builder Pattern)

    建造者模式(Builder Pattern)是最復雜的創(chuàng)建型模式,它 用于創(chuàng)建一個包含多個組成部分的復雜對象 ,可以返回一個完整的產(chǎn)品對象給用戶。它通過將 客戶端與包含多個組成部分的復雜對象的創(chuàng)建過程分離 ,使得 客戶端無需知道復雜對象的內(nèi)部組成部分與裝配方式,只需要

    2024年02月03日
    瀏覽(24)
  • 建造者模式-Builder Pattern

    建造者模式-Builder Pattern

    原文地址:https://jaune162.blog/design-pattern/builder-pattern/ 現(xiàn)在一般大型的業(yè)務系統(tǒng)中的消息通知的形式都會有多種,比如短信、站內(nèi)信、釘釘通知、郵箱等形式。雖然信息內(nèi)容相同,但是展現(xiàn)形式缺不同。如短信使用的是純文本的形式,釘釘使用的一般是Markdown的形式,而郵箱則

    2024年02月20日
    瀏覽(33)
  • Builder Pattern —— Structure Class

    建造者模式又稱為 生成器模式 ,主要用于對復雜對象的構建、初始化,它可以 將多個簡單的組件對象按順序一步步組裝起來 , 最終構建成一個復雜的成品對象 。 與工廠系列模式不同的是,建造者模式的主要目的在于把煩瑣的 構建過程 從不同對象中抽離出來,使其脫離并

    2024年02月10日
    瀏覽(21)
  • 設計模式--建造者模式(Builder Pattern)

    設計模式--建造者模式(Builder Pattern)

    建造者模式(Builder Pattern)是一種創(chuàng)建型設計模式,它關注如何按照一定的步驟和規(guī)則創(chuàng)建復雜對象。建造者模式的主要目的是將一個復雜對象的構建過程與其表示分離,從而使同樣的構建過程可以創(chuàng)建不同的表示。 在建造者模式中,通常有以下幾個核心角色: 產(chǎn)品(Prod

    2024年02月11日
    瀏覽(18)
  • 設計模式|建造者模式(Builder Pattern)

    建造者模式(Builder Pattern)是一種創(chuàng)建型設計模式,用于將一個復雜對象的構建過程與其表示分離,以便可以使用相同的構建過程創(chuàng)建不同的表示。 Builder(建造者)接口或抽象類 : 定義了構建對象的各個步驟的方法。 ConcreteBuilder(具體建造者)類 : 實現(xiàn)了 Builder 接口或繼

    2024年04月15日
    瀏覽(40)
  • 設計模式——建造者模式(Builder Pattern)

    設計模式——建造者模式(Builder Pattern)

    概述 ?????? 建造者模式是較為復雜的創(chuàng)建型模式,它將客戶端與包含多個組成部分(或部件)的復雜對象的創(chuàng)建過程分離,客戶端無須知道復雜對象的內(nèi)部組成部分與裝配方式,只需要知道所需建造者的類型即可。它關注如何一步一步創(chuàng)建一個的復雜對象,不同的具體建

    2024年01月20日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包