中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Fluent API創建更簡單、更直觀的代碼

發布時間:2022-02-24 13:46:20 來源:億速云 閱讀:171 作者:小新 欄目:開發技術

這篇文章給大家分享的是有關如何使用Fluent API創建更簡單、更直觀的代碼的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

什么是 Fluent-API?

當我們在軟件工程的上下文中談論時,fluent-API 是一種面向對象的 API,其設計主要基于方法鏈。

這個概念由Eric EvansMartin Fowler于 2005 年創建,旨在通過創建特定領域語言 ( DSL )來提高代碼可讀性。

在實踐中,創建一個流暢的 API 意味著開發一個 API,其中不需要記住接下來的步驟或方法,允許一個自然連續的序列,就好像它是一個選項菜單。

這種自然的節奏與餐廳甚至快餐連鎖店的工作方式類似,因為當您將一道菜放在一起時,選項會根據你所做的選擇而有所不同。例如,如果你選擇雞肉三明治,則會根據所選菜肴等建議配菜。

Java 上下文中的 Fluent API

在 Java 世界中,我們可以想到此類實現的兩個著名示例。

第一個是JOOQ框架,這是一個由Lukas Eder領導的項目,它促進了 Java 和關系數據庫之間的通信。JOOQ 最顯著的區別在于它是面向數據的,這有助于避免和/或減少與關系和面向對象相關的阻抗問題或損失。

Query query = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
                    .from(BOOK)
                    .join(AUTHOR)
                    .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
                    .where(BOOK.PUBLISHED_IN.eq(1948));

String sql = query.getSQL();
List<Object> bindValues = query.getBindValues();

另一個例子是在企業 Java 世界規范內的非關系數據庫,即 NoSQL。其中包括Jakarta EE,它是同類中的第一個規范,并成為Eclipse Foundation旗下的Jakarta NoSQL。

本規范的目的是確保 Java 和 NoSQL 數據庫之間的順暢通信。

DocumentQuery query = select().from("Person").where(eq(Document.of("_id", id))).build();
Optional<Person> person = documentTemplate.singleResult(query);
System.out.println("Entity found: " + person);

一般來說,一個 fluent API 分為三個部分:

  1. 最終的對象或結果:總的來說,fluent-API 類似于構建器模式,但最強大的動態與 DSL 相結合。在這兩種情況下,結果往往是代表流程或新實體結果的實例。

  2. 選項:在這種情況下,是將用作“我們的交互式菜單”的接口或類的集合。從一個動作來看,這個想法是按照直觀的順序只顯示下一步可用的選項。

  3. 結果:在所有這個過程之后,答案可能會或可能不會導致實體、策略等的實例。關鍵點是結果必須是有效的。

流體 API 實踐

為了演示這一概念,我們將創建一個三明治訂單,其中包含具有相應購買價格的訂單的預期結果。流程如下所示。

如何使用Fluent API創建更簡單、更直觀的代碼

當然,有多種方法可以實現這種流暢的 API 功能,但我們選擇了一個簡短的版本。

正如我們已經提到的 API 的三個部分——對象、選項和結果——我們將從“訂單”接口將表示的順序開始。一個亮點是這個界面有一些界面,它們將負責展示我們的選項。

public interface Order {


    interface SizeOrder {
        StyleOrder size(Size size);
    }

    interface StyleOrder {

        StyleQuantityOrder vegan();

        StyleQuantityOrder meat();
    }

    interface StyleQuantityOrder extends DrinksOrder {
        DrinksOrder quantity(int quantity);
    }


    interface DrinksOrder {
        Checkout softDrink(int quantity);

        Checkout cocktail(int quantity);

        Checkout softDrink();

        Checkout cocktail();

        Checkout noBeveragesThanks();
    }

    static SizeOrder bread(Bread bread) {
        Objects.requireNonNull(bread, "Bread is required o the order");
        return new OrderFluent(bread);
    }

這個 API 的結果將是我們的訂單類。它將包含三明治、飲料及其各自的數量。

在我們返回教程之前的快速附加組件

我們不會在本文中關注但值得一提的一點與貨幣的表示有關。

當涉及到數值運算時,最好使用 BigDecimal。那是因為,根據Java Effective書籍和博客When Make a Type 之類的參考資料,我們了解到復雜類型需要唯一的類型。這種推理,再加上“不要重復自己”的實用主義,結果就是使用了 Java 貨幣規范:The Money API

import javax.money.MonetaryAmount;
import java.util.Optional;

public class Checkout {

    private final Sandwich sandwich;

    private final int quantity;

    private final Drink drink;

    private final int drinkQuantity;

    private final MonetaryAmount total;

  //...
}

旅程的最后一步是 API 實現。它將負責代碼的“丑陋”部分,使 API 看起來很漂亮。

由于我們不使用數據庫或其他數據引用,因此價格表將直接放置在代碼中,并且我們打算使示例盡可能簡單。但值得強調的是,在自然環境中,這些信息會存在于數據庫或服務中。

import javax.money.MonetaryAmount;
import java.util.Objects;

class OrderFluent implements Order.SizeOrder, Order.StyleOrder, Order.StyleQuantityOrder, Order.DrinksOrder {

    private final PricingTables pricingTables = PricingTables.INSTANCE;

    private final Bread bread;

    private Size size;

    private Sandwich sandwich;

    private int quantity;

    private Drink drink;

    private int drinkQuantity;

    OrderFluent(Bread bread) {
        this.bread = bread;
    }

    @Override
    public Order.StyleOrder size(Size size) {
        Objects.requireNonNull(size, "Size is required");
        this.size = size;
        return this;
    }

    @Override
    public Order.StyleQuantityOrder vegan() {
        createSandwich(SandwichStyle.VEGAN);
        return this;
    }

    @Override
    public Order.StyleQuantityOrder meat() {
        createSandwich(SandwichStyle.MEAT);
        return this;
    }

    @Override
    public Order.DrinksOrder quantity(int quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("You must request at least one sandwich");
        }
        this.quantity = quantity;
        return this;
    }

    @Override
    public Checkout softDrink(int quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("You must request at least one sandwich");
        }
        this.drinkQuantity = quantity;
        this.drink = new Drink(DrinkType.SOFT_DRINK, pricingTables.getPrice(DrinkType.SOFT_DRINK));
        return checkout();
    }

    @Override
    public Checkout cocktail(int quantity) {
        if (quantity <= 0) {
            throw new IllegalArgumentException("You must request at least one sandwich");
        }
        this.drinkQuantity = quantity;
        this.drink = new Drink(DrinkType.COCKTAIL, pricingTables.getPrice(DrinkType.COCKTAIL));
        return checkout();
    }

    @Override
    public Checkout softDrink() {
        return softDrink(1);
    }

    @Override
    public Checkout cocktail() {
        return cocktail(1);
    }

    @Override
    public Checkout noBeveragesThanks() {
        return checkout();
    }

    private Checkout checkout() {
        MonetaryAmount total = sandwich.getPrice().multiply(quantity);
        if (drink != null) {
            MonetaryAmount drinkTotal = drink.getPrice().multiply(drinkQuantity);
            total = total.add(drinkTotal);
        }
        return new Checkout(sandwich, quantity, drink, drinkQuantity, total);
    }

    private void createSandwich(SandwichStyle style) {
        MonetaryAmount breadPrice = pricingTables.getPrice(this.bread);
        MonetaryAmount sizePrice = pricingTables.getPrice(this.size);
        MonetaryAmount stylePrice = pricingTables.getPrice(SandwichStyle.VEGAN);
        MonetaryAmount total = breadPrice.add(sizePrice).add(stylePrice);
        this.sandwich = new Sandwich(style, this.bread, this.size, total);
    }
}

結果是一個 API,它將直接直觀地將請求返回給我們。

Checkout checkout = Order.bread(Bread.PLAIN)
           .size(Size.SMALL)
           .meat()
           .quantity(2)
           .softDrink(2);

Fluent API 與其他模式有何不同?

對兩種 API 標準進行比較是很普遍的,它們是 Builder 和 Fluent-API。原因是它們在創建實例的過程中都按順序使用方法。

但是,Fluent-API 是“與 DSL 相關聯的”,它強制采用一種簡單的方法來實現這一點。但為了使這些差異更加明顯,我們為每個模式分別列出了亮點:

Builder 模式:

  • 它往往更容易實施;

  • 不清楚需要哪些施工方法;

  • 絕大多數問題都會在運行時發生;

  • 一些工具和框架會自動創建它;

  • 它需要在 build 方法中進行更健壯的驗證,以檢查哪些強制方法沒有被調用。

流利的API:

  • 重要的是,對于每個方法,都有驗證,如果參數無效則拋出錯誤,記住快速失敗的前提;

  • 它必須在過程結束時返回一個有效的對象。

現在,是否更容易理解模式之間的異同?

這就是我們對 fluent-API 概念的介紹。與所有解決方案一樣,沒有“靈丹妙藥”,因為整個過程通常不合理。

它是一個出色的工具,有助于為你和其他用戶創建故障保護。

感謝各位的閱讀!關于“如何使用Fluent API創建更簡單、更直觀的代碼”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

长乐市| 商河县| 图木舒克市| 曲沃县| 临朐县| 边坝县| 乐陵市| 九江县| 苍山县| 台北市| 秦安县| 元朗区| 永修县| 平武县| 岢岚县| 合肥市| 东至县| 渑池县| 舞阳县| 龙南县| 上饶县| 安福县| 根河市| 南宫市| 哈巴河县| 尼勒克县| 湟中县| 错那县| 长兴县| 玉田县| 德阳市| 缙云县| 泸定县| 玉环县| 会理县| 西丰县| 琼结县| 高邮市| 焦作市| 贡觉县| 崇文区|