解釋器模式
1.簡介
解釋器模式(Interpreter Pattern)是一種行為設(shè)計(jì)模式,它用于定義語言的文法,并且解釋語言中的表達(dá)式。在Java中,解釋器模式可以用于構(gòu)建解釋器以解析特定的語言或表達(dá)式,如數(shù)學(xué)表達(dá)式、查詢語言等。
優(yōu)點(diǎn):
-
靈活性: 解釋器模式可以
靈活地添加新的表達(dá)式和規(guī)則
,因此適用于處理不斷變化的語言或表達(dá)式。 - 易擴(kuò)展性: 可以輕松地?cái)U(kuò)展文法,添加新的解釋器,而不會影響現(xiàn)有的解釋器。
-
簡化語法分析: 將文法規(guī)則
分解成一個個小的解釋器
,使得語法分析更加簡單和清晰。 -
易于實(shí)現(xiàn): 每個表達(dá)式都可以由一個簡單的解釋器實(shí)現(xiàn),
降低了系統(tǒng)的復(fù)雜度
,易于實(shí)現(xiàn)和維護(hù)
。
缺點(diǎn):
- 復(fù)雜度高: 對于復(fù)雜的文法規(guī)則,需要創(chuàng)建大量的解釋器對象,可能會導(dǎo)致類爆炸問題,增加系統(tǒng)的復(fù)雜度。
- 執(zhí)行效率低: 解釋器模式通常采用遞歸調(diào)用的方式進(jìn)行解釋,可能會導(dǎo)致解釋過程比較耗時,執(zhí)行效率低下。
- 維護(hù)困難: 隨著文法的變化和解釋器的增加,維護(hù)成本可能會增加,特別是在處理復(fù)雜語言時。
使用場景:
-
特定領(lǐng)域語言(DSL)解析: 適用于需要解析和執(zhí)行特定領(lǐng)域語言的場景,如
數(shù)學(xué)表達(dá)式
、正則表達(dá)式
、查詢語言
等。 -
規(guī)則引擎: 用于
構(gòu)建規(guī)則引擎
,根據(jù)不同的規(guī)則執(zhí)行相應(yīng)的操作。 - 編譯器和解釋器設(shè)計(jì): 可用于編寫編譯器和解釋器,將源代碼轉(zhuǎn)換成目標(biāo)代碼或執(zhí)行相應(yīng)的操作。
-
配置文件解析: 適用于解析配置文件,
將配置信息轉(zhuǎn)換成相應(yīng)的對象或操作
。
2.案例-生成SQL建表語句
需求描述:
假設(shè)我們需要開發(fā)一個簡單的數(shù)據(jù)庫表生成工具,它可以根據(jù)用戶提供的列信息生成相應(yīng)的 SQL 建表語句。用戶可以指定表名、列名、數(shù)據(jù)類型等信息,并且可以選擇是否設(shè)置列為主鍵、非空等約束。
用戶需求:
- 用戶希望能夠指定表名以及列的詳細(xì)信息,包括列名、數(shù)據(jù)類型、長度等。
- 用戶希望能夠選擇是否將某列設(shè)置為主鍵、非空等約束。
- 用戶希望能夠生成符合特定數(shù)據(jù)庫類型的建表語句,例如 PostgreSQL、MySQL 等。
實(shí)現(xiàn)思路:
-
定義抽象表達(dá)式接口:
- 創(chuàng)建一個接口,定義解釋方法
interpret()
,該方法將返回解釋后的結(jié)果。
- 創(chuàng)建一個接口,定義解釋方法
-
創(chuàng)建終結(jié)符表達(dá)式類:
- 實(shí)現(xiàn)抽象表達(dá)式接口的類,用于表示文法中的最小單元。
- 包含需要解釋的數(shù)據(jù)和解釋方法的具體實(shí)現(xiàn)。
-
創(chuàng)建非終結(jié)符表達(dá)式類:
- 實(shí)現(xiàn)抽象表達(dá)式接口的類,用于表示文法中的復(fù)合結(jié)構(gòu)。
- 包含其他表達(dá)式對象或者其他操作的組合,并實(shí)現(xiàn)解釋方法。
-
創(chuàng)建環(huán)境類(Context):
- 封裝解釋器需要的數(shù)據(jù)和方法。
- 提供執(zhí)行解釋器的方法,并返回結(jié)果。
- 解耦解釋器與客戶端代碼:
Context
提供統(tǒng)一接口,客戶端代碼不需要直接操作解釋器,降低了耦合度。 - 封裝解釋器的創(chuàng)建邏輯:
Context
封裝解釋器的創(chuàng)建邏輯,使客戶端代碼更簡潔,只需調(diào)用Context
方法即可執(zhí)行解釋器。 - 統(tǒng)一的異常處理機(jī)制:
Context
提供統(tǒng)一異常處理,捕獲解釋器執(zhí)行過程中的異常,進(jìn)行統(tǒng)一處理,如記錄日志、返回錯誤信息。 - 支持?jǐn)U展和替換解釋器: 可以通過修改
Context
中的創(chuàng)建邏輯來引入新的解釋器實(shí)現(xiàn)或替換現(xiàn)有實(shí)現(xiàn),提高系統(tǒng)的靈活性和可擴(kuò)展性。
-
客戶端代碼:
- 創(chuàng)建具體的終結(jié)符和非終結(jié)符表達(dá)式對象。
- 創(chuàng)建環(huán)境對象,將表達(dá)式對象傳遞給環(huán)境對象。
- 調(diào)用環(huán)境對象的解釋方法,獲取解釋結(jié)果。
2.1.實(shí)現(xiàn)
2.1.1.抽共享表達(dá)式接口
/**
* 定義抽象表達(dá)式接口
* @author 13723
* @version 1.0
* 2024/2/6 10:01
*/
public interface Expression {
/**
* 解釋方法
* @return 解釋結(jié)果
*/
String interpret();
}
2.1.2.終結(jié)符表達(dá)式類
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 終結(jié)符實(shí)現(xiàn)類
* 終結(jié)符(Terminal Symbol):在文法中,終結(jié)符是指不能進(jìn)一步被分解的符號或標(biāo)記。
* 在語法分析過程中,終結(jié)符是輸入字符的最小單元。終結(jié)符是文法的基本元素,通常代表實(shí)際的詞匯或標(biāo)記。
* 文法中的每一個終結(jié)符都有一個具體終結(jié)表達(dá)式與之相對應(yīng)。
*/
@Getter @Setter
@NoArgsConstructor
public class ColumnExpression implements Expression {
/**
* 列名
*/
private String name;
/**
* 列類型
*/
private String type;
/**
* 列長度
*/
private String length;
/**
* 注釋
*/
private String comment;
/**
* 是否是主鍵
*/
private Boolean primaryKey = false;
/**
* 是否是非空
*/
private Boolean notNull = false;
public ColumnExpression(String name, String type, String length) {
this.name = name;
this.type = type;
this.length = length;
}
public ColumnExpression(String name, String type, String length, String comment) {
this.name = name;
this.type = type;
this.length = length;
this.comment = comment;
}
public ColumnExpression(String name, String type, String length, String comment, Boolean notNull) {
this.name = name;
this.type = type;
this.length = length;
this.comment = comment;
this.notNull = notNull;
}
public ColumnExpression(String name, String type, String length, String comment, Boolean primaryKey, Boolean notNull) {
this.name = name;
this.type = type;
this.length = length;
this.primaryKey = primaryKey;
this.notNull = notNull;
this.comment = comment;
}
@Override
public String interpret() {
StringBuilder sb = new StringBuilder();
sb.append("\t").append("\"").append(name).append("\"").append(" ").append(type).append("(").append(length).append(")");
// 如果設(shè)置了不為空,根據(jù)數(shù)據(jù)類型添加 NOT NULL
if (notNull) {
if ("VARCHAR".equals(type) || "CHAR".equals(type) || "TEXT".equals(type) || "BLOB".equals(type) || "CLOB".equals(type) || "NCLOB".equals(type)){
sb.append(" COLLATE \"pg_catalog\".\"default\" NOT NULL" );
}else {
sb.append(" NOT NULL");
}
}
return sb.toString();
}
}
2.1.3.非終結(jié)符表達(dá)式類
package com.hrfan.java_se_base.pattern.Interpreter_pattern.se;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 非終結(jié)符(Nonterminal Symbol):非終結(jié)符是可以被進(jìn)一步分解的符號或標(biāo)記,在文法規(guī)則中用來描述語言的結(jié)構(gòu)和組織。
* 非終結(jié)符通常代表語法結(jié)構(gòu)中的一類元素,可以是語法規(guī)則的左側(cè)或右側(cè)的一部分。
* 文法中的每條規(guī)則都對應(yīng)于一個非終結(jié)符表達(dá)式。
*/
@Getter @Setter
public class TableExpression implements Expression{
private String tableName;
private List<ColumnExpression> columns;
public TableExpression(String tableName) {
this.tableName = tableName;
this.columns = new ArrayList<>();
}
// 添加列
public void addColumn(ColumnExpression column) {
columns.add(column);
}
// 獲取設(shè)置主鍵的數(shù)據(jù)
public List<String> getColumnPrimaryKey(){
List<String> collect = columns.stream().filter(ColumnExpression::getPrimaryKey).map(ColumnExpression::getName).collect(Collectors.toList());
return collect;
}
// 設(shè)置注釋 和 字段名稱
public Map<String,String> getColumnComment(){
Map<String, String> map = columns.stream().filter(it -> StringUtils.isNotBlank(it.getComment())).collect(Collectors.toMap(ColumnExpression::getName, ColumnExpression::getComment));
return map;
}
@Override
public String interpret() {
// 獲取主鍵的列名
List<String> columnPrimaryKey = getColumnPrimaryKey();
StringBuilder sb = new StringBuilder("\nCREATE TABLE \"gwstd\".\"" + tableName + "\" " + "(" + "\n");
for (int i = 0; i < columns.size(); i++) {
// 執(zhí)行非終結(jié)符解釋邏輯
sb.append(columns.get(i).interpret());
if (i < columns.size() - 1 || columnPrimaryKey.size() > 0){
sb.append(", \n");
}
}
if (columnPrimaryKey.size() > 0){
sb.append("\tCONSTRAINT ").append("\"").append(tableName).append("_pkey\"").append("PRIMARY KEY (");
for (int i = 0; i < columnPrimaryKey.size(); i++) {
sb.append("\"").append(columnPrimaryKey.get(i)).append("\"");
if (i < columnPrimaryKey.size() - 1) {
sb.append(",");
}
}
sb.append(")\n");
}
sb.append(");");
// 生成輸入語句
sb.append("\n");
sb.append("ALTER TABLE \"gwstd\".").append("\"").append(tableName).append("\"").append(" OWNER TO \"postgres\"").append(";");
// 生成注釋
Map<String, String> columnComment = getColumnComment();
if (!columnComment.isEmpty()){
for (Map.Entry<String, String> entry : columnComment.entrySet()) {
sb.append("\n");
// COMMENT ON COLUMN "gwstd"."t_dec_order_head"."sid" IS '主鍵Sid';
sb.append("COMMENT ON COLUMN \"gwstd\".").append("\"").append(tableName).append("\"").append(".").append("\"").append(entry.getKey()).append("\"").append(" IS '").append(entry.getValue()).append("';");
}
}
return sb.toString();
}
}
2.1.4.創(chuàng)建Context(承上啟下)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
/**
* @author 13723
* @version 1.0
* 2024/2/6 10:17
*/
public class Context {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/**
* 建表語句表達(dá)式
*/
private Expression expression;
public Context(){
}
/**
* 解釋方法
*/
public Context(Expression expression){
this.expression = expression;
}
/**
* 執(zhí)行解釋方法
* @return 解釋結(jié)果
*/
public String interpret(){
return expression.interpret();
}
}
2.1.5.測試類
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
/**
* @author 13723
* @version 1.0
* 2024/2/6 10:20
*/
public class ExpressCreateTest {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Test
@DisplayName("測試建表語句解釋器")
public void test(){
// 創(chuàng)建表對象(使用建造者模式構(gòu)建表對象)
TableExpressionBuilder builder = new TableExpressionBuilder("t_dec_erp_test_students");
// 非終結(jié)符解釋器 中 添加 終結(jié)符解釋器
// 字段名稱,字段類型,字段長度,字段注釋,是否為主鍵,是否為空
builder.addColumn(new ColumnExpression("sid", "VARCHAR", "11","主鍵sid",true,true))
.addColumn(new ColumnExpression("name", "VARCHAR", "255","姓名"))
.addColumn(new ColumnExpression("age", "NUMERIC", "3","年齡",true))
.addColumn(new ColumnExpression("email", "VARCHAR", "255","郵箱",true))
.addColumn(new ColumnExpression("address", "VARCHAR", "255","聯(lián)系地址"))
.addColumn(new ColumnExpression("telephone", "VARCHAR", "255","聯(lián)系電話"));
// 構(gòu)建表達(dá)式
TableExpression expression = builder.build();
// 通過Context執(zhí)行解釋方法,獲取解釋結(jié)果.
String interpret = new Context(expression).interpret();
logger.error("最終生成sql:\n{}",interpret);
}
}
CREATE TABLE "gwstd"."t_dec_erp_test_students" (
"sid" VARCHAR(11) COLLATE "pg_catalog"."default" NOT NULL,
"name" VARCHAR(255),
"age" NUMERIC(3) NOT NULL,
"email" VARCHAR(255) COLLATE "pg_catalog"."default" NOT NULL,
"address" VARCHAR(255),
"telephone" VARCHAR(255),
CONSTRAINT "t_dec_erp_test_students_pkey"PRIMARY KEY ("sid")
);
ALTER TABLE "gwstd"."t_dec_erp_test_students" OWNER TO "postgres";
COMMENT ON COLUMN "gwstd"."t_dec_erp_test_students"."address" IS '聯(lián)系地址';
COMMENT ON COLUMN "gwstd"."t_dec_erp_test_students"."name" IS '姓名';
COMMENT ON COLUMN "gwstd"."t_dec_erp_test_students"."telephone" IS '聯(lián)系電話';
COMMENT ON COLUMN "gwstd"."t_dec_erp_test_students"."email" IS '郵箱';
COMMENT ON COLUMN "gwstd"."t_dec_erp_test_students"."age" IS '年齡';
COMMENT ON COLUMN "gwstd"."t_dec_erp_test_students"."sid" IS '主鍵sid';
2.2.Spring使用場景
2.2.1.Spring-SpEL
Spring表達(dá)式語言(SpEL)允許在運(yùn)行時動態(tài)計(jì)算值,它可以用于配置文件、注解等多種場景中。在SpEL的背后,實(shí)際上就是使用了解釋器模式。
Spring框架中,與Spring EL(表達(dá)式語言)相關(guān)的類位于org.springframework.expression
包下。以下是幾個與Spring EL密切相關(guān)的類的簡要介紹:
-
SpelExpression: 代表一個EL表達(dá)式,它在內(nèi)部通過抽象語法樹(AST)來表示表達(dá)式。EL表達(dá)式的求值是通過調(diào)用
this.ast.getValue(expressionState);
來實(shí)現(xiàn)的。 -
ExpressionParser: 表達(dá)式解析器接口,定義了解析EL表達(dá)式的方法。Spring提供了
SpelExpressionParser
作為默認(rèn)的表達(dá)式解析器實(shí)現(xiàn)。 - StandardEvaluationContext: 標(biāo)準(zhǔn)的評估上下文,用于在表達(dá)式求值期間存儲變量和函數(shù)。它提供了用于設(shè)置變量和函數(shù)的方法,這些變量和函數(shù)可以在EL表達(dá)式中使用。
-
EvaluationContext: 評估上下文接口,用于在表達(dá)式求值期間提供變量和函數(shù)的訪問。
StandardEvaluationContext
是EvaluationContext
接口的實(shí)現(xiàn)之一。 - SpelNode: SpEL語法樹的節(jié)點(diǎn),代表了EL表達(dá)式的各個部分。每個節(jié)點(diǎn)都有自己的類型和操作,用于實(shí)現(xiàn)EL表達(dá)式的解析和求值。
2.2.1.1.案例代碼
@Test
@DisplayName("測試@Value")
public void test2(){
// 1. 構(gòu)建解析器
ExpressionParser parser = new SpelExpressionParser();
// 2. 解析表達(dá)式
Expression expression = parser.parseExpression("100 * 2 + 200 * 1 + 100000");
// 3. 獲取結(jié)果
int result = (Integer) expression.getValue();
// 4. 打印結(jié)果
logger.error("result:{}",result);
}
語法樹
抽象語法樹(Abstract Syntax Tree,AST)是一種用于表示編程語言代碼結(jié)構(gòu)的樹形數(shù)據(jù)結(jié)構(gòu)。
在編譯器和解釋器中,AST是一種常見的數(shù)據(jù)結(jié)構(gòu),用于表示程序代碼的語法結(jié)構(gòu)和語義信息
。
在Java中,AST抽象語法樹是指代表Java源代碼結(jié)構(gòu)的樹形數(shù)據(jù)結(jié)構(gòu)。它由多個節(jié)點(diǎn)組成,每個節(jié)點(diǎn)代表源代碼中的一個語法元素,例如表達(dá)式、語句、方法調(diào)用等。AST的根節(jié)點(diǎn)表示整個程序的起始點(diǎn),而子節(jié)點(diǎn)則代表程序中的具體語法結(jié)構(gòu)。
# 語法樹
+
/ \
* +
/ \ / \
100 2 * 100000
/ \
200 1
2.2.1.2.SpelExpression
SpelExpression 是 Spring 表達(dá)式語言(SpEL)中的一個組成部分,用于表達(dá)特定的表達(dá)式。它內(nèi)部采用抽象語法樹(AST)來表示表達(dá)式的結(jié)構(gòu)。計(jì)算表達(dá)式的值是通過調(diào)用 this.ast.getValue(expressionState);
實(shí)現(xiàn)的。在這個過程中,AST被用來解釋和執(zhí)行表達(dá)式,最終得到表達(dá)式的計(jì)算結(jié)果。
public class SpelExpression implements Expression {
@Nullable
public Object getValue() throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
EvaluationContext context = this.getEvaluationContext();
return compiledAst.getValue(context.getRootObject().getValue(), context);
} catch (Throwable var4) {
if (this.configuration.getCompilerMode() != SpelCompilerMode.MIXED) {
throw new SpelEvaluationException(var4, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION, new Object[0]);
}
}
this.compiledAst = null;
this.interpretedCount.set(0);
}
ExpressionState expressionState = new ExpressionState(this.getEvaluationContext(), this.configuration);
Object result = this.ast.getValue(expressionState);
this.checkCompile(expressionState);
return result;
}
}
2.2.1.2.SpelNodeImpl
SpelNodeImpl 是 Spring 表達(dá)式語言(SpEL)中的關(guān)鍵類,用于表示已解析的表達(dá)式在抽象語法樹(AST)中的節(jié)點(diǎn)。
在解釋器模式中,AST 的節(jié)點(diǎn)充當(dāng)了終結(jié)符和非終結(jié)符的角色,幫助構(gòu)建表達(dá)式的結(jié)構(gòu)。
SpelNodeImpl 的子類包括以下幾種類型:
- Literal: 代表各種類型值的父類。
- Operator: 代表各種操作符的父類。
- Indexer 等:代表其他類型的節(jié)點(diǎn)。
public abstract class SpelNodeImpl implements SpelNode, Opcodes {
private static final SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
protected SpelNodeImpl[] children;
@Nullable
private SpelNodeImpl parent;
@Nullable
protected final <T> T getValue(ExpressionState state, Class<T> desiredReturnType) throws EvaluationException {
return ExpressionUtils.convertTypedValue(state.getEvaluationContext(), this.getValueInternal(state), desiredReturnType);
}
// 抽象方法子類實(shí)現(xiàn),獲取對象值
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
}
2.2.1.3.IntLiteral
IntLiteral 表示整型文字的表達(dá)式語言的ast結(jié)點(diǎn)
public class IntLiteral extends Literal {
private final TypedValue value;
public IntLiteral(String payload, int startPos, int endPos, int value) {
super(payload, startPos, endPos);
this.value = new TypedValue(value);
this.exitTypeDescriptor = "I";
}
public TypedValue getLiteralValue() {
return this.value;
}
//
}
2.2.1.4.OpPlus
OpPlus 表示加法的ast結(jié)點(diǎn),在 getValueInternal 方法中對操作符兩邊進(jìn)行相加操作
public class OpPlus extends Operator {
private static final int MAX_CONCATENATED_STRING_LENGTH = 100000;
public OpPlus(int startPos, int endPos, SpelNodeImpl... operands) {
super("+", startPos, endPos, operands);
Assert.notEmpty(operands, "Operands must not be empty");
}
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
SpelNodeImpl leftOp = this.getLeftOperand();
if (this.children.length < 2) {
Object operandOne = leftOp.getValueInternal(state).getValue();
if (operandOne instanceof Number) {
if (operandOne instanceof Double) {
this.exitTypeDescriptor = "D";
} else if (operandOne instanceof Float) {
this.exitTypeDescriptor = "F";
} else if (operandOne instanceof Long) {
this.exitTypeDescriptor = "J";
} else if (operandOne instanceof Integer) {
this.exitTypeDescriptor = "I";
}
return new TypedValue(operandOne);
} else {
return state.operate(Operation.ADD, operandOne, (Object)null);
}
} else {
// 遞歸調(diào)用leftOp的 getValueInternal(state) ,獲取操作符左邊的值
TypedValue operandOneValue = leftOp.getValueInternal(state);
Object leftOperand = operandOneValue.getValue();
// 遞歸調(diào)用children[1]的 getValueInternal(state) ,獲取操作符右邊的值
TypedValue operandTwoValue = this.getRightOperand().getValueInternal(state);
Object rightOperand = operandTwoValue.getValue();
// 如果操作符左右都是數(shù)值類型,則將它們相加
if (leftOperand instanceof Number && rightOperand instanceof Number) {
Number leftNumber = (Number)leftOperand;
Number rightNumber = (Number)rightOperand;
if (!(leftNumber instanceof BigDecimal) && !(rightNumber instanceof BigDecimal)) {
if (!(leftNumber instanceof Double) && !(rightNumber instanceof Double)) {
if (!(leftNumber instanceof Float) && !(rightNumber instanceof Float)) {
if (!(leftNumber instanceof BigInteger) && !(rightNumber instanceof BigInteger)) {
if (!(leftNumber instanceof Long) && !(rightNumber instanceof Long)) {
if (!CodeFlow.isIntegerForNumericOp(leftNumber) && !CodeFlow.isIntegerForNumericOp(rightNumber)) {
return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue());
} else {
this.exitTypeDescriptor = "I";
return new TypedValue(leftNumber.intValue() + rightNumber.intValue());
}
} else {
this.exitTypeDescriptor = "J";
return new TypedValue(leftNumber.longValue() + rightNumber.longValue());
}
} else {
BigInteger leftBigInteger = (BigInteger)NumberUtils.convertNumberToTargetClass(leftNumber, BigInteger.class);
BigInteger rightBigInteger = (BigInteger)NumberUtils.convertNumberToTargetClass(rightNumber, BigInteger.class);
return new TypedValue(leftBigInteger.add(rightBigInteger));
}
} else {
this.exitTypeDescriptor = "F";
return new TypedValue(leftNumber.floatValue() + rightNumber.floatValue());
}
} else {
this.exitTypeDescriptor = "D";
return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue());
}
} else {
BigDecimal leftBigDecimal = (BigDecimal)NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = (BigDecimal)NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return new TypedValue(leftBigDecimal.add(rightBigDecimal));
}
} else {
String rightString;
String leftString;
if (leftOperand instanceof String && rightOperand instanceof String) {
this.exitTypeDescriptor = "Ljava/lang/String";
rightString = (String)leftOperand;
leftString = (String)rightOperand;
this.checkStringLength(rightString);
this.checkStringLength(leftString);
return this.concatenate(rightString, leftString);
} else if (leftOperand instanceof String) {
rightString = (String)leftOperand;
this.checkStringLength(rightString);
leftString = rightOperand == null ? "null" : convertTypedValueToString(operandTwoValue, state);
this.checkStringLength(leftString);
return this.concatenate(rightString, leftString);
} else if (rightOperand instanceof String) {
rightString = (String)rightOperand;
this.checkStringLength(rightString);
leftString = leftOperand == null ? "null" : convertTypedValueToString(operandOneValue, state);
this.checkStringLength(leftString);
return this.concatenate(leftString, rightString);
} else {
return state.operate(Operation.ADD, leftOperand, rightOperand);
}
}
}
}
}
解釋器模式相對于其他設(shè)計(jì)模式確實(shí)在實(shí)際應(yīng)用中使用較少,這主要是由于以下幾個原因:文章來源:http://www.zghlxwxcb.cn/news/detail-827284.html
- 復(fù)雜性和性能開銷: 解釋器模式的實(shí)現(xiàn)可能會引入較高的復(fù)雜性和性能開銷。解釋器需要對輸入進(jìn)行解析、分析和執(zhí)行,這可能導(dǎo)致性能上的損失,并且隨著解釋器規(guī)則的增多,代碼的復(fù)雜度也會增加。
- 不易理解和維護(hù): 解釋器模式的實(shí)現(xiàn)通常較為復(fù)雜,需要設(shè)計(jì)者對語法和語義有深入的理解,同時需要維護(hù)大量的解釋器規(guī)則。這使得解釋器模式在代碼的可讀性和可維護(hù)性方面存在挑戰(zhàn)。
- 有限的適用場景: 解釋器模式通常適用于特定領(lǐng)域的問題,例如編譯器、正則表達(dá)式引擎等。在許多常見的軟件開發(fā)場景中,并不經(jīng)常需要使用解釋器模式來解決問題。
- 其他替代方案: 對于一些需要解釋和執(zhí)行邏輯的問題,通常有更簡單、更高效的替代方案,例如使用編譯器、腳本引擎、規(guī)則引擎等。這些替代方案能夠更直接地執(zhí)行邏輯,而不需要通過解釋器的中間層。
盡管解釋器模式在一些特定的領(lǐng)域和場景下仍然有其價(jià)值,但在許多常見的軟件開發(fā)任務(wù)中,它并不是第一選擇。因此,雖然解釋器模式是一種重要的設(shè)計(jì)模式,但其應(yīng)用相對較少。文章來源地址http://www.zghlxwxcb.cn/news/detail-827284.html
到了這里,關(guān)于解鎖Spring Boot中的設(shè)計(jì)模式—02.解釋器模式:探索【解釋器模式】的奧秘與應(yīng)用實(shí)踐!的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!