精华内容
下载资源
问答
  • 设计模式 | 解释器模式及典型应用

    千次阅读 2019-01-13 23:47:54
    微信原文:设计模式 | 解释器模式及典型应用 博客原文:设计模式 | 解释器模式及典型应用 本文主要介绍解释器模式,在日常开发中,解释器模式的使用频率比较低 解释器模式 解释器模式(Interpreter Pattern):定义一...

    微信原文:设计模式 | 解释器模式及典型应用
    博客原文:设计模式 | 解释器模式及典型应用

    本文主要介绍解释器模式,在日常开发中,解释器模式的使用频率比较低

    解释器模式

    解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的 “语言” 是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。

    角色

    AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。

    TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。

    NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。

    Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。

    解释器模式结构图

    示例

    使用解释器模式实现一个简单的后缀表达式解释器,仅支持对整数的加法和乘法即可

    定义抽象表达式接口

    public interface Interpreter {
        int interpret();
    }
    

    非终结符表达式,对整数进行解释

    public class NumberInterpreter implements Interpreter {
        private int number;
    
        public NumberInterpreter(int number) {
            this.number = number;
        }
    
        public NumberInterpreter(String number) {
            this.number = Integer.parseInt(number);
        }
    
        @Override
        public int interpret() {
            return this.number;
        }
    }
    

    终结符表达式,对加法和乘法进行解释

    // 加法
    public class AddInterpreter implements Interpreter {
        private Interpreter firstExpression, secondExpression;
        public AddInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
            this.firstExpression = firstExpression;
            this.secondExpression = secondExpression;
        }
        @Override
        public int interpret() {    
            return this.firstExpression.interpret() + this.secondExpression.interpret();
        }
        @Override
        public String toString() {
            return "+";
        }
    }
    
    // 乘法
    public class MultiInterpreter implements Interpreter {
        private Interpreter firstExpression, secondExpression;
    
        public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
            this.firstExpression = firstExpression;
            this.secondExpression = secondExpression;
        }
        @Override
        public int interpret() {
            return this.firstExpression.interpret() * this.secondExpression.interpret();
        }
        @Override
        public String toString() {
            return "*";
        }
    }
    

    工具类

    public class OperatorUtil {
        public static boolean isOperator(String symbol) {
            return (symbol.equals("+") || symbol.equals("*"));
    
        }
        public static Interpreter getExpressionObject(Interpreter firstExpression, Interpreter secondExpression, String symbol) {
            if ("+".equals(symbol)) {  // 加法
                return new AddInterpreter(firstExpression, secondExpression);
            } else if ("*".equals(symbol)) {    // 乘法
                return new MultiInterpreter(firstExpression, secondExpression);
            } else {
                throw new RuntimeException("不支持的操作符:" + symbol);
            }
        }
    }
    

    测试,对后缀表达式 6 100 11 + * 进行求值

    public class Test {
        public static void main(String[] args) {
            String inputStr = "6 100 11 + *";
            MyExpressionParser expressionParser = new MyExpressionParser();
            int result = expressionParser.parse(inputStr);
            System.out.println("解释器计算结果: " + result);
        }
    }
    

    运行结果

    入栈: 6
    入栈: 100
    入栈: 11
    出栈: 11 和 100
    应用运算符: +
    阶段结果入栈: 111
    出栈: 111 和 6
    应用运算符: *
    阶段结果入栈: 666
    解释器计算结果: 666
    

    示例.类图

    解释器模式总结

    解释器模式为自定义语言的设计和实现提供了一种解决方案,它用于定义一组文法规则并通过这组文法规则来解释语言中的句子。虽然解释器模式的使用频率不是特别高,但是它在正则表达式XML文档解释等领域还是得到了广泛使用。

    主要优点

    • 易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
    • 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言
    • 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。
    • 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合 “开闭原则”。

    主要缺点

    • 对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
    • 执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

    适用场景

    • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
    • 一些重复出现的问题可以用一种简单的语言来进行表达。
    • 一个语言的文法较为简单。
    • 对执行效率要求不高。

    解释器模式的典型应用

    Spring EL表达式中的解释器模式

    Spring EL表达式相关的类在 org.springframework.expression 包下,类图如下

    org.springframework.expression 包的类图

    涉及的类非常多,这里仅对此时我们最关心的几个类做介绍:

    SpelExpression,表示一个 EL 表达式,表达式在内部通过一个 AST抽象语法树 表示,EL表达式求值是通过 this.ast.getValue(expressionState); 求值

    public class SpelExpression implements Expression {
    	private final String expression;
    	private final SpelNodeImpl ast;
    	private final SpelParserConfiguration configuration;
    	
    	@Override
    	@Nullable
    	public Object getValue() throws EvaluationException {
    		if (this.compiledAst != null) {
    			try {
    				EvaluationContext context = getEvaluationContext();
    				return this.compiledAst.getValue(context.getRootObject().getValue(), context);
    			}
    			catch (Throwable ex) {
    				// If running in mixed mode, revert to interpreted
    				if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
    					this.interpretedCount = 0;
    					this.compiledAst = null;
    				}
    				else {
    					// Running in SpelCompilerMode.immediate mode - propagate exception to caller
    					throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
    				}
    			}
    		}
    
    		ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
    		Object result = this.ast.getValue(expressionState);
    		checkCompile(expressionState);
    		return result;
    	}
    	//...省略...
    }
    

    SpelNodeImpl:已解析的Spring表达式所代表的ast语法树的节点的通用父类型,语法树的节点在解释器模式中扮演的角色是终结符和非终结符。从类图中可以看到,SpelNodeImpl 的子类主要有 Literal,Operator,Indexer等,其中 Literal 是各种类型的值的父类,Operator 则是各种操作的父类

    public abstract class SpelNodeImpl implements SpelNode, Opcodes {
    	protected int pos;  // start = top 16bits, end = bottom 16bits
    	protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
    	@Nullable
    	private SpelNodeImpl parent;
    
    	public final Object getValue(ExpressionState expressionState) throws EvaluationException {
    		return getValueInternal(expressionState).getValue();
    	}
        // 抽象方法,由子类实现,获取对象的值
    	public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
    	//...省略...
    }
    

    IntLiteral 表示整型文字的表达式语言的ast结点

    public class IntLiteral extends Literal {
        private final TypedValue value;
    	public IntLiteral(String payload, int pos, int value) {
    		super(payload, pos);
    		this.value = new TypedValue(value); // 
    		this.exitTypeDescriptor = "I";
    	}
    	@Override
    	public TypedValue getLiteralValue() {
    		return this.value;
    	}
    	// ...
    }
    

    OpPlus 表示加法的ast结点,在 getValueInternal 方法中对操作符两边进行相加操作

    public class OpPlus extends Operator {
    	public OpPlus(int pos, SpelNodeImpl... operands) {
    		super("+", pos, operands);
    		Assert.notEmpty(operands, "Operands must not be empty");
    	}
    	@Override
    	public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
    		SpelNodeImpl leftOp = getLeftOperand();
    
    		if (this.children.length < 2) {  // if only one operand, then this is unary plus
    			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);
    			}
    			return state.operate(Operation.ADD, operandOne, null);
    		}
            // 递归调用leftOp的 getValueInternal(state) ,获取操作符左边的值
    		TypedValue operandOneValue = leftOp.getValueInternal(state);
    		Object leftOperand = operandOneValue.getValue();
    		// 递归调用children[1]的 getValueInternal(state) ,获取操作符右边的值
    		TypedValue operandTwoValue = getRightOperand().getValueInternal(state);
    		Object rightOperand = operandTwoValue.getValue();
    
            // 如果操作符左右都是数值类型,则将它们相加
    		if (leftOperand instanceof Number && rightOperand instanceof Number) {
    			Number leftNumber = (Number) leftOperand;
    			Number rightNumber = (Number) rightOperand;
                
    			if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
    				BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
    				BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
    				return new TypedValue(leftBigDecimal.add(rightBigDecimal));
    			}
    			else if (leftNumber instanceof Double || rightNumber instanceof Double) {
    				this.exitTypeDescriptor = "D";  
    				return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue());
    			}
    			//...省略 Float->F, BigInteger->add, Long->J,Integer->I
    			else {
    				// Unknown Number subtypes -> best guess is double addition
    				return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue());
    			}
    		}
    		//...
    		return state.operate(Operation.ADD, leftOperand, rightOperand);
    	}
        //...
    }
    

    通过一个示例,调试查看程序中间经历的步骤

    public class SpringELTest {
        public static void main(String[] args) {
            // 1. 构建解析器
            org.springframework.expression.ExpressionParser parser = new SpelExpressionParser();
            // 2. 解析表达式
            Expression expression = parser.parseExpression("100 * 2 + 400 * 1 + 66");
            // 3. 获取结果
            int result = (Integer) expression.getValue();
            System.out.println(result); // 结果:666
        }
    }
    

    EL表达式解析后得到表达式 (((100 * 2) + (400 * 1)) + 66)
    EL表达式解析后得到的表达式

    如果用图形把其这棵AST抽象语法树简单地画出来,大概是这样

    示例.AST抽象语法树

    调用 expression.getValue() 求值,此时的 ast 是语法树的头结点,也就是 + OpPlus,所以通过 this.ast.getValue(expressionState) 进入了 OpPlus 的 getValue 方法(是父类中的方法),接着进入 getValueInternal 方法,然后递归计算操作符左边的值,递归计算操作符右边的值,最后相加返回

    示例.spring EL调试

    参考:
    刘伟.Java设计模式
    Java设计模式精讲

    后记

    欢迎评论、转发、分享

    更多内容可访问我的个人博客:http://laijianfeng.org

    关注【小旋锋】微信公众号,及时接收博文推送

    关注_小旋锋_微信公众号

    展开全文
  • 2.15 典型正则表达式解释(1)

    千次阅读 2008-03-24 14:11:00
    本小节解释基于正则表达式的基础理论的典型正则表达式,如匹配Windows操作系统的名称、匹配HTML标记、匹配HTML标记之间的内容。 1.匹配Windows操作系统的名称 Windows操作系统存在很多版本,如Windows 95、...

      本小节解释基于正则表达式的基础理论的典型正则表达式,如匹配Windows操作系统的名称、匹配HTML标记、匹配HTML标记之间的内容。

      1.匹配Windows操作系统的名称

      Windows操作系统存在很多版本,如Windows 95Windows 98Windows 2000Windows MEWindows XPWindows 2003等。以下正则表达式能够精确匹配Windows操作系统的名称。

    Windows/s*((95)|(98)|(2000)|(2003)|(ME)|(XP))                      81

      上述表达式能够精确匹配Windows 95Windows 98Windows 2000Windows MEWindows XPWindows 2003等操作系统的名称。然而,精确匹配Windows操作系统的名称的正则表达式比较冗长。以下      正则表达式能够简单匹配Windows操作系统的名称。

    Windows/s/w+                                                             82

      2.匹配HTML标记

      HTML标记一般被尖括号包围,如<a><table><br><input>等。以下正则表达式能够匹配HTML标记。

    <[a-zA-Z][^>]*>                                                                  83

      正则表达式(83)解释:

          <匹配HTML标记的左尖括号。

          字符类[a-zA-Z]可以匹配一个英文字母,它匹配HTML标记中第一个字符(除去左尖括号)。

          字符类[^>]可以匹配除右尖括号的之外的任何字符。

          [^>]*可以匹配空字符串,或者由除右尖括号的之外的任何字符组成的字符串。

          >匹配HTML标记的右尖括号。

          [a-zA-Z][^>]*匹配HTML标记的名称。

      使用工具Regex Tester测试正则表达式(83),结果如图所示。

     

     

     
    展开全文
  • 一张图解释典型编译程序结构框图

    千次阅读 2017-10-04 11:10:14
    编译程序结构框图

    编译程序结构框图

    这里写图片描述

    展开全文
  • 1.注册流程: 2.注销流程: 3. 基本呼叫建立过程: 4. 会话更改流程: 5. 正常呼叫释放过程: 6. 被叫忙呼叫释放: 7.被叫无应答流程一: 8.被叫无应答流程二: 9.遇忙呼叫前转: ... 

    1.注册流程:

    2.注销流程:

    3. 基本呼叫建立过程:

    4. 会话更改流程:

    5. 正常呼叫释放过程:

    6. 被叫忙呼叫释放:

    7.被叫无应答流程一:

    8.被叫无应答流程二:

    9.遇忙呼叫前转:

    10.无应答呼叫前转流程:

    11.呼叫保持:

    12.呼叫等等:

     

     


     

    1.注册流程:

     

     

     

     

     

     

    2.注销流程:

     

     

     

     

     

     

     

     

    3. 基本呼叫建立过程:

     

     

     

     

     

     

    4. 会话更改流程:

     

     

     

     

     

     

    5. 正常呼叫释放过程:

     

     

     

    6. 被叫忙呼叫释放:

     

     

     

     

    7.被叫无应答流程一:

     

     

     

     

     

     

    8.被叫无应答流程二:

     

     

     

     

     

    9.遇忙呼叫前转:

     

     

     

     

     

    10.无应答呼叫前转流程:

     

     

     

    11.呼叫保持:

     

     

     

    12.呼叫等等:

     

    13、资料汇总

    呼叫保持

    呼叫等待

    呼叫前转

    会议

     

    Transfer

    Refe

    Conference

    Forward

     

    中国电信 第三分册 信令流程

    http://www.vocal.com/sip/index.html

    SIP Calling

    SIP Conferencing

    SIP Call Forwarding

    SIP Call Transferring

    Locating SIP Servers

    SIP Message Routing

    SIP PRACK

    SIP Presence and Instant Messaging

    SIP Registration

    Secure SIP

    SIP and Deep Packet Inspection (DPI)

    SIP Session Timers

    SIP Datasheet

    RFC 3261 Standard

    http://tools.ietf.org/html/draft-ietf-sip-cc-transfer-05

    http://tools.ietf.org/html/draft-ietf-sip-refer-00

     

     

     

    SIP呼叫转移(Refer)的信令流程

    (2007-03-27 13:20:51)

    转载

     

    分类: VoIP技术

     

     

    这是按照我们自己实现的流程画的,希望大家指正

     

     

     

     

     

     

     

     

     

     

     转自:http://blog.csdn.net/braveyly/article/details/6420282

     

    展开全文
  • 原文地址:《一文看懂深度学习(白话解释+8个优缺点+4个典型算法)》 深度学习有很好的表现,引领了第三次人工智能的浪潮。目前大部分表现优异的应用都用到了深度学习,大红大紫的 AlphaGo 就使用到了深度学习。 ...
  • [+] 注册流程注销流程基本呼叫建立过程会话更改流程正常呼叫释放过程被叫忙呼叫释放被叫无应答流程一被叫无应答流程二遇忙呼叫前转无应答呼叫前转流程呼叫保持呼叫等等 ...1 2.注销流程:... 3 ...
  • 装饰器本质上是个python函数,实现是由闭包支撑的 应用场景: 1,引入日志 2,函数执行时间统计 3,执行函数前预备处理 4,执行函数后清理功能 5,权限校验等场景 6,缓存 7,事务处理 ...
  • 当访问到包含需要解释器的元素节点时,则会启动解释器做解释操作,根据维护的文法Expression类型,调用getStringValue,并传入参数Environment, 相应类型的表达式根据Environment解释得到输入字符串的值,返回并...
  • 典型相关分析

    千次阅读 2018-11-28 11:01:17
    典型相关分析中的CANCORR过程。
  • 典型推荐算法总结

    万次阅读 多人点赞 2018-11-23 21:05:42
    推荐算法种类很多,但是目前应用最广泛的应该是协同过滤类别的推荐算法,本文就对协同过滤类别的推荐算法做一个概括总结,后续也会对一些典型的协同过滤推荐算法做原理总结。 1. 推荐算法概述  推荐算法是非常...
  • 典型相关分析系列博文: 典型相关分析(Canonical correlation analysis)(一):基本思想 、复相关系数、偏相关系数 典型相关分析(Canonical correlation analysis)(二):原始变量与典型变量之间的相关性 、...
  • 典型相关分析及R应用

    万次阅读 2018-11-04 23:35:49
    目录 什么是典型相关分析 典型相关分析基本架构 简单相关分析 ...用于探讨一组解释变量-亦即预测变量与一组反应变量间的关系即是典型相关分析-canonical correlation analysis,比如在体育训练中,...
  • SAS 典型相关分析

    千次阅读 2017-02-28 18:26:13
    /*--------------------典型相关分析-----------------------------------*/ /*-----用力肺活量指标和呼气流速指标的相关关系------*/ data hq(type=corr); /*指定输入数据为相关系数矩阵*/ input _name_$3.x1 ...
  • R语言典型相关分析

    万次阅读 多人点赞 2017-02-27 16:40:46
    部分参考薛毅的《统计建模与R软件》和《R语言实战》1 关键点:典型相关分析典型相关分析是用于分析两组随机变量之间的相关程度的一种统计方法,它能够有效地揭示两组随机变量之间的相互(线性依赖)关系例如 研究生...
  • 典型相关分析系列博文: 典型相关分析(Canonical correlation analysis)(一):基本思想 、复相关系数、偏相关系数 典型相关分析(Canonical correlation analysis)(二):原始变量与典型变量之间的相关性 ...
  • 典型销售面试问题

    千次阅读 2012-10-11 10:26:18
    典型销售人员面试问题 浏览: 16058 | 更新: 2012-02-17 15:58 | 标签: 面试  17  6 简介 典型销售人员面试问题。在销售人员面试时,面试官往往会准备一些...
  • R语言 典型相关分析

    千次阅读 2016-05-05 14:50:25
    1 关键点:#典型相关分析# #典型相关分析是用于分析两组随机变量之间的相关程度的一种统计方法,它能够有效地揭示两组随机变量之间的相互(线性依赖)关系 #例如 研究生入学考试成绩与本科阶段一些主要课程成绩的...
  • 一、为什么要用典型相关分析 典型相关分析研究的是两组变量之间的关系,如{x1, x2, x3}和{y1, y2, y3}两组变量之间的关系。 具体来说,变量间的相关关系可以分为以下几种: 两个变量间的线性相关关系,可用简单相关...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 258,323
精华内容 103,329
关键字:

典型怎么解释