引言
你有没有想过,为什么计算器能理解 2 + 3 * 4 这样的表达式?为什么 Excel 的公式能正确计算出结果?这一切都离不开一个强大的设计模式——解释器模式。
今天我们就用最轻松的方式,一起来探索这个模式的奥秘!
解释器模式到底是什么?
简单一句话理解
解释器模式就像一个翻译官,它把你定义的"语言"翻译成计算机能理解的指令。
举个生活中的例子
想象一下你在使用智能音箱:
你说:"打开客厅的空调,设定26度"智能音箱的处理过程:1. 解析:"打开空调" + "客厅" + "设定温度" + "26度"2. 理解:先找到客厅的空调设备,然后设置温度为263. 执行:发送控制指令
这个过程,就是解释器模式在工作!
核心角色
解释器模式有4个核心角色,用通俗的话说:
实战案例:表达式计算器
让我们从最简单的例子开始——实现一个能计算数学表达式的计算器。
想象一下
如果要计算 (2 + 3) * 4,计算机是怎么做的?
第一步:识别各个数字和符号 2 + 3 * 4第二步:理解运算顺序(括号优先,乘除优先于加减) 先算 (2 + 3) = 5 再算 5 * 4 = 20第三步:得到结果 20
这个过程,就是解释器的工作方式!
动手实现
1️.定义"翻译规范"(抽象表达式)
// 所有表达式都要遵守的规则publicinterfaceIExpression{intInterpret(); // 翻译并返回结果}
2️.定义"基础词汇"(终结符表达式)
// 数字是最基础的词汇publicclassNumberExpression : IExpression{privatereadonlyint _number;publicNumberExpression(int number) { _number = number; }publicintInterpret() {return _number; // 数字直接返回自己 }}
3️.定义"语法规则"(非终结符表达式)
// 加法规则publicclassAddExpression : IExpression{privatereadonly IExpression _left; // 左边表达式privatereadonly IExpression _right; // 右边表达式publicAddExpression(IExpression left, IExpression right) { _left = left; _right = right; }publicintInterpret() {// 先翻译左边和右边,然后相加return _left.Interpret() + _right.Interpret(); }}// 减法规则publicclassSubtractExpression : IExpression{privatereadonly IExpression _left;privatereadonly IExpression _right;publicSubtractExpression(IExpression left, IExpression right) { _left = left; _right = right; }publicintInterpret() {return _left.Interpret() - _right.Interpret(); }}// 乘法规则publicclassMultiplyExpression : IExpression{privatereadonly IExpression _left;privatereadonly IExpression _right;publicMultiplyExpression(IExpression left, IExpression right) { _left = left; _right = right; }publicintInterpret() {return _left.Interpret() * _right.Interpret(); }}
4️.开始使用!
classProgram{staticvoidMain(string[] args) {// 示例1:计算 2 + 3// 构建语法树:Add(2, 3)var expr1 = new AddExpression(new NumberExpression(2),new NumberExpression(3) ); Console.WriteLine($"2 + 3 = {expr1.Interpret()}");// 示例2:计算 (2 + 3) * 4// 构建语法树:Multiply(Add(2, 3), 4)var expr2 = new MultiplyExpression(new AddExpression(new NumberExpression(2),new NumberExpression(3) ),new NumberExpression(4) ); Console.WriteLine($"(2 + 3) * 4 = {expr2.Interpret()}");// 示例3:复杂表达式 10 - 3 * 2// 构建语法树:Subtract(10, Multiply(3, 2))var expr3 = new SubtractExpression(new NumberExpression(10),new MultiplyExpression(new NumberExpression(3),new NumberExpression(2) ) ); Console.WriteLine($"10 - 3 * 2 = {expr3.Interpret()}"); }}
运行结果如下:
语法树长什么样?
以 (2 + 3) * 4 为例:
Multiply / \ Add 4 / \ 2 3
解释器从下往上翻译:
- 3. 最后翻译 Multiply(5, 4),得到 20
实战案例:灵活的查询语言
现在我们来看一个更贴近实际工作的场景——构建一个简单的查询系统。
场景描述
假设我们有一个员工列表,想要灵活地查询:
传统的写法可能是:
// 写死在代码里,每次修改都要重新编译if (emp.Department == "开发部" && emp.City == "北京"){// ...}
而用解释器模式,我们可以动态组合查询条件!
实现思路和过程
1️.定义查询表达式接口
// 所有查询表达式都要实现这个接口publicinterfaceIQueryExpression{boolMatch(Dictionary<string, string> employee);}
2️. 实现基本条件
// 等于条件:字段 == 值publicclassEqualsExpression : IQueryExpression{privatereadonlystring _fieldName;privatereadonlystring _value;publicEqualsExpression(string fieldName, stringvalue) { _fieldName = fieldName; _value = value; }publicboolMatch(Dictionary<string, string> employee) {return employee.ContainsKey(_fieldName) && employee[_fieldName] == _value; }}// 包含条件:字段.Contains(值)publicclassContainsExpression : IQueryExpression{privatereadonlystring _fieldName;privatereadonlystring _value;publicContainsExpression(string fieldName, stringvalue) { _fieldName = fieldName; _value = value; }publicboolMatch(Dictionary<string, string> employee) {return employee.ContainsKey(_fieldName) && employee[_fieldName].Contains(_value); }}
3️.实现逻辑组合
// AND 条件:两个条件都满足publicclassAndExpression : IQueryExpression{privatereadonly IQueryExpression _left;privatereadonly IQueryExpression _right;publicAndExpression(IQueryExpression left, IQueryExpression right) { _left = left; _right = right; }publicboolMatch(Dictionary<string, string> employee) {return _left.Match(employee) && _right.Match(employee); }}// OR 条件:满足其中一个即可publicclassOrExpression : IQueryExpression{privatereadonly IQueryExpression _left;privatereadonly IQueryExpression _right;publicOrExpression(IQueryExpression left, IQueryExpression right) { _left = left; _right = right; }publicboolMatch(Dictionary<string, string> employee) {return _left.Match(employee) || _right.Match(employee); }}// NOT 条件:不满足条件publicclassNotExpression : IQueryExpression{privatereadonly IQueryExpression _expression;publicNotExpression(IQueryExpression expression) { _expression = expression; }publicboolMatch(Dictionary<string, string> employee) {return !_expression.Match(employee); }}
4️. 灵活使用
classProgram{staticvoidMain(string[] args) {// 准备测试数据var employees = new List<Dictionary<string, string>> {new Dictionary<string, string> { { "name", "张三" }, { "dept", "开发部" }, { "city", "北京" } },new Dictionary<string, string> { { "name", "李四" }, { "dept", "开发部" }, { "city", "上海" } },new Dictionary<string, string> { { "name", "王五" }, { "dept", "产品部" }, { "city", "北京" } } };// 查询1:开发部 AND 北京var query1 = new AndExpression(new EqualsExpression("dept", "开发部"),new EqualsExpression("city", "北京") ); Console.WriteLine(" 查询1:开发部 AND 北京"); Console.WriteLine("匹配结果:");foreach (var emp in employees) {if (query1.Match(emp)) Console.WriteLine($" {emp["name"]}"); }// 查询2:北京 OR 上海var query2 = new OrExpression(new EqualsExpression("city", "北京"),new EqualsExpression("city", "上海") ); Console.WriteLine("\n查询2:北京 OR 上海"); Console.WriteLine("匹配结果:");foreach (var emp in employees) {if (query2.Match(emp)) Console.WriteLine($" {emp["name"]}"); }// 查询3:NOT 产品部var query3 = new NotExpression(new EqualsExpression("dept", "产品部") ); Console.WriteLine("\n查询3:NOT 产品部"); Console.WriteLine("匹配结果:");foreach (var emp in employees) {if (query3.Match(emp)) Console.WriteLine($" {emp["name"]}"); } }}
运行结果如下:
最酷的是什么?
你现在可以随意组合查询条件,就像搭积木一样:
// 查找:(开发部 AND 北京) OR (产品部 AND 上海)var complexQuery = new OrExpression(new AndExpression(new EqualsExpression("dept", "开发部"),new EqualsExpression("city", "北京") ),new AndExpression(new EqualsExpression("dept", "产品部"),new EqualsExpression("city", "上海") ));
而且,这些查询可以在运行时动态构建,不需要重新编译代码!
什么时候该用?
✅ 适合使用的场景
❌ 不适合使用的场景
.NET 中的实际应用
你每天都在用解释器模式,只是可能没注意到!
LINQ 表达式树
// 这就是一个表达式树Expression<Func<int, int, int>> addExpr = (a, b) => a + b;// 编译并执行var addFunc = addExpr.Compile();int result = addFunc(3, 4); // 结果: 7
正则表达式
// 正则表达式引擎就是一个解释器var pattern = @"\d{3}-\d{4}"; // 匹配电话号码var input = "我的电话:010-1234";var match = Regex.Match(input, pattern);if (match.Success){ Console.WriteLine($"找到电话: {match.Value}");}
写在最后
解释器模式的核心思想是: 将复杂的语言语法,分解成简单的、可组合的表达式解释器模式虽然不是最常用的设计模式,但在特定场景下非常强大。掌握它,你就能:
✅ 设计灵活的规则引擎✅ 实现可配置的业务逻辑✅ 理解 LINQ 和正则表达式背后的原理
设计模式不是死的公式,而是活的思维。关键是理解它解决的问题,然后在实际工作中灵活应用!