首頁 > 軟體

Java如何構造DSL方法重構

2022-07-07 18:05:37

DSL

Domain-specific language: 一種專注於某一領域,僅針對部分表達方式的計算機程式語言。

特點

  • 方法鏈 Method Chaining
  • 功能序列 Functional Sequence
  • 巢狀函數 Nested Functions 巢狀函數
  • Lambda表示式/閉包 Lambda Expressions/Closures

概念有點抽象,先看程式碼吧

假設你想發一些郵件,你需要一個類能夠方便的設定收信人、發信人、標題、內容。

一個傳統的java api(具體業務程式碼都省略了):

public class Mailer {
    public void from(String fromAddress) {
    }
    public void to(String toAddress) {
    }
    public void subject(String theSubject) {
    }
    public void message(String body) {
    }
    public void send() {
    }
}

測試要這樣寫:

public static void main(String[] args) {
    Mailer mailer = new Mailer();
    mailer.from("build@example.com");
    mailer.to("example@example.com");
    mailer.subject("build notification");
    mailer.message("some details about build status");
    mailer.send();
}

我們可以做些重構,使這個api更流暢,更像DSL。

package dsl.example;
public class Mailer {
    public Mailer from(String fromAddress) {
        return this;
    }
    public Mailer to(String toAddress) {
        return this;
    }
    public Mailer subject(String theSubject) {
        return this;
    }
    public Mailer message(String body) {
        return this;
    }
    public void send() {
    }
}

這樣看起來好多了,但是如果能消除new就更好了。因為使用者的興趣在於傳送郵件,而不是在建立物件。

public static void main(String[] args) {
    new Mailer()
        .from("build@example.com")
        .to("example@example.com")
        .subject("build notification")
        .message("some details about build status")
        .send();
}

測試:

public static void main(String[] args) {
    Mailer.mail()
        .from("build@example.com")
        .to("example@example.com")
        .subject("build notification")
        .message("some details about build status")
        .send();
}

可以做一下靜態匯入

public static void main(String[] args) {
    import static dsl.example.Mailer.mail;mail()  
        .from("build@example.com")  
        .to("example@example.com")  
        .subject("build notification")  
        .message("some details about build status")  
        .send();
}

這樣,一個DSL的語句就完成了。一般來說,使用Java編寫的DSL不會造就一門業務使用者可以上手的語言,而會是一種業務使用者也會覺得易讀的語言,同時,從程式設計師的角度,它也會是一種閱讀和編寫都很直接的語言。

小結

建立DSL最好的方法是,首先將所需的API原型化,然後在基礎語言的約束下將它實現。DSL的實現將會牽涉到連續不斷的測試來肯定我們的開發確實瞄準了正確的方向。該“原型-測試”方法正是測試驅動開發模式(TDD-Test-Driven Development)所提倡的。

其實JDK8提供的很多api已經有很多內部DSL的語意,比如Stream流的find、count等操作都是一種DSL的語意表達,本文只是簡單的說明了如何構造DSL,有機會計劃找一個實際的業務程式碼用DSL的方式重構,敬請期待。


IT145.com E-mail:sddin#qq.com