設計模式之直譯器模式

2022-09-06 18:02:04

直譯器模式字面意思,也即解釋某些內容的含義。這種設計模式是實際開發中最不容易用到的。比如SQL解析,符號處理引擎,會用到直譯器模式,屬於更底層的開發人員才會用到的設計模式。

本文就以直譯器模式的概念、角色和簡單的例子說明直譯器模式,讀者對這部分內容瞭解即可。

一、概念

直譯器模式是指給定一門語言,定義它的文法的一種表示(如:加減乘除表示式和正規表示式等),然後再定義一個直譯器,該直譯器用來解釋我們的文法表示(表示式)。

直譯器模式的結構與組合模式相似,不過其包含的組成元素比組合模式多,而且組合模式是物件結構型模式,而直譯器模式是類行為型模式。

直譯器模式中包含四個角色:

  1. 抽象直譯器(Abstract Expression)角色:定義直譯器的介面,約定直譯器的解釋操作,主要包含解釋方法 interpret()。

  2. 終結符直譯器(Terminal Expression)角色:是抽象表示式的子類,用來實現文法中與終結符相關的操作,文法中的每一個終結符都有一個具體終結表示式與之相對應。

  3. 非終結符直譯器(Nonterminal Expression)角色:也是抽象表示式的子類,用來實現文法中與非終結符相關的操作,文法中的每條規則都對應於一個非終結符表示式。

  4. 環境(Context)角色:通常包含各個直譯器需要的資料或是公共的功能,一般用來傳遞被所有直譯器共用的資料,後面的直譯器可以從這裡獲取這些值。

    直譯器模式類結構圖如圖所示:

二、實現

接下來針對四個角色分別定義他們的實現。

抽象直譯器:

/**
 * 宣告一個抽象的解釋操作,這個介面為抽象語法樹中所有的節點所共用
 * @author tcy
 * @Date 29-08-2022
 */
public abstract class AbstractExpression {

    public abstract boolean interpret(String info);
}

非終結符表示式:

/**
 * 非終結符表示式,為文法中的非終結符實現解釋操作。對文法中每一條規則R1、R2...Rn都需要一個具體的非終結符表示式類
 * @author tcy
 * @Date 29-08-2022
 */
public class NonTerminalExpression extends AbstractExpression{

    private AbstractExpression address=null;
    private AbstractExpression name=null;
    private AbstractExpression id=null;

    public NonTerminalExpression(AbstractExpression address, AbstractExpression name, AbstractExpression id) {
        this.address = address;
        this.name = name;
        this.id = id;
    }


    @Override
    public boolean interpret(String info) {
        String s[]=info.split("-");
        return address.interpret(s[0])&&name.interpret(s[1])&&id.interpret(s[2]);
    }
}

終結符表示式:

**
 * 實現與文法中的終結符相關聯的解釋操作,文法中每一個終結符都有一個具體終結表示式與之相對應
 * @author tcy
 * @Date 29-08-2022
 */
public class TerminalExpression extends AbstractExpression{

    private Set<String> set =new HashSet<String>();

    public TerminalExpression(String[] data)
    {
        for(int i=0; i<data.length;i++)
            set.add(data[i]);
    }


    @Override
    public boolean interpret(String info) {
        if(set.contains(info))
        {
            return true;
        }
        return false;
    }
}

上下文環境:

/**
 * 上下文環境
 * @author tcy
 * @Date 29-08-2022
 */
public class Context {
    private String[] shuzis={"1","2","3","4","5","6","7","8","9","0"};
    private String[] xiaoxiezimus={"a","b","c","d","e","f","g","h","i","j","k","l"};
    private String[] daxiezimus={"A","B","C","D","E","F","G"};
    private AbstractExpression infomation;

    public Context()
    {
        AbstractExpression shuzi=new TerminalExpression(shuzis);
        AbstractExpression xiaoxiezimu=new TerminalExpression(xiaoxiezimus);
        AbstractExpression daxiezimu=new TerminalExpression(daxiezimus);
        infomation=new NonTerminalExpression(shuzi,xiaoxiezimu,daxiezimu);
    }

    public void jieshi(String info)
    {
        boolean ok=infomation.interpret(info);
        if(ok) System.out.println("正確! ["+info+"] 滿足  [單個數位-單個小寫-單個大寫]  的條件");
        else System.out.println("錯誤! ["+info+"] 不滿足  [單個數位-單個小寫-單個大寫]  的條件");
    }

}

使用者端:

/**
 * @author tcy
 * @Date 29-08-2022
 */
public class Client {
    public static void main(String[] args) {
        Context people=new Context();
        people.jieshi("2-a-A");
        people.jieshi("11-A-5");
        people.jieshi("你-好-吖");
        people.jieshi("2aA");

    }
}

以上為直譯器模式的簡單案例,讀者可以拉取程式碼到本地進行學習。

三、應用場景

直譯器模式在實際的軟體開發中使用比較少,因為它會引起效率、效能以及維護等問題。

在JDK中的正規表示式中的Pattern類和Spring裡面的ExpressionParse介面使用的是直譯器模式的思想。

當一個語言需要解釋執行,並且語言中的句子可以表示為一個抽象語法樹的時候,如 XML 檔案解釋,整體來說還是一種應用較少的設計模式。

已經連續更新了數十篇設計模式部落格,推薦你結合學習。

一、設計模式概述

二、設計模式之工廠方法和抽象工廠

三、設計模式之單例和原型

四、設計模式之建造者模式

五、設計模式之代理模式

六、設計模式之介面卡模式

七、設計模式之橋接模式

八、設計模式之組合模式

九、設計模式之裝飾器模式

十、設計模式之外觀模式

十一、外觀模式之享元模式

十二、設計模式之責任鏈模式

十三、設計模式之命令模式