设计模式13-中介模式与解释器模式详解
1.13.中介模式与解释器模式详解
1.13.1.中介模式详解
时长:49min
13.1.1.中介模式的定义
定义:
中介者模式【Mediator Pattern】,又称调解者模式或调停者模式。用一个中介对象封装一系列的对象
交互,中介者使用各对象不需要显式地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
核心:
通过中介者解耦系统各层次对象的直接耦合,层次对象的对外依赖通信统统交由中介者转发。
属于行为型模式。
13.1.1.1.中介者模式在生活场景中应用
1.人际交往圈,通讯网络。如果需要自己逐个去建立关系会很困难且复杂,如果加入中介者,来维护这个网络。
中介者就很方便了。
2.朋友圈。
3.数据整合中心
4.rpc通信
13.1.1.2.中介者模式的使用场景
1.系统中对象之间存在复杂的引用关系,产生相互依赖关系结构混乱且难以理解。
2.交互的公共行为,如果需要改变行为则可以增加新的中介者类。
13.1.2.中介模式的通用实现
13.1.2.1.类图设计
13.1.2.2.代码实现
13.1.3.中介模式应用案例之聊天室
很多人进入一个聊天室,或聊天群里,群或聊天室,都充当中介者的角色。
13.1.3.1.类图设计
说明:
这里通过用户名,表示不同用户。
13.1.3.2.代码实现
1.中介者【聊天室】
package com.wf.mediator.demo.chatroom; /** * @ClassName ChatRoom * @Description 聊天室 * @Author wf * @Date 2020/6/23 10:31 * @Version 1.0 */ public class ChatRoom { public void showMsg(User user,String message){ System.out.println("【"+user.getName() +"】,传达信息:"+message); } }
它就只是一个传话者,把信息发布者的内容,传达出来。
2.用户类【聊天者】
package com.wf.mediator.demo.chatroom; /** * @ClassName User * @Description 用户类 * @Author wf * @Date 2020/6/23 10:32 * @Version 1.0 */ public class User { private ChatRoom chatRoom; private String name; public String getName() { return name; } public User(String name,ChatRoom chatRoom) { this.chatRoom = chatRoom; this.name = name; } public void sendMessage(String msg){ //用户传达信息,通过聊天室 this.chatRoom.showMsg(this, msg); } }
3.测试类
package com.wf.mediator.demo.chatroom; /** * @ClassName Test * @Description 测试类 * @Author wf * @Date 2020/6/23 10:37 * @Version 1.0 */ public class Test { public static void main(String[] args) { ChatRoom chatRoom = new ChatRoom(); User tom = new User("Tom",chatRoom); User jerry = new User("Jerry",chatRoom); tom.sendMessage("大家好,我是"+tom.getName()+"欢迎大家,进入聊天室"); jerry.sendMessage("大家好,我是"+jerry.getName()+"欢迎大家,进入聊天室"); } }
测试结果:
13.1.4.中介者模式在源码中应用
13.1.4.1.jdk中Timer类
private void sched(TimerTask task, long time, long period) { if (time < 0) throw new IllegalArgumentException("Illegal execution time."); // Constrain value of period sufficiently to prevent numeric // overflow while still being effectively infinitely large. if (Math.abs(period) > (Long.MAX_VALUE >> 1)) period >>= 1; synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } queue.add(task); if (queue.getMin() == task) queue.notify(); } }
Timer类中有多个schedule重载方法,内部都调用sched方法,Timer本身是没有做什么事的。
它只是调用Quequ队列add,把TimerTask添加进去。所以,Timer充当中介者的角色。
13.1.5.中介者模式使用总结
13.1.5.1.优缺点总结
优点:
1.减少类间依赖,将多对多依赖关系,转化成一对多的关系,降低了类间的耦合性。
2.类间各司其职,符合迪米特法则。
缺点:
中介者模式,将原本多个对象直接的相互依赖关系,变成依赖中介者和多个同事类的依赖关系。
当同事类越来越多时,中介者责任越来越大,且复杂难以维护。
13.1.5.2.与其他模式的关系总结
中介者模式和代理模式的区别:
1.都存在中间角色。
2.代理模式,着重在代理【增强功能】
3.中介者模式,只他帮你联系上了,就不管了,后面的事情全权由自己完成。【只管搭桥】
1.13.2.解释器模式详解
13.2.1.解释器模式的定义
定义:
解释器模式【Interpretor Pattern】给定一个语言,定义它的文法的一种表示,并定义解释器。
这个解释器使用该表示来解释语言中的句子。
特征:
为了解释一种语言,而为语言创建的解释器。
属于行为型模式。
13.2.1.1.解释器模式在生活场景中应用
1.音乐简谱
2.摩斯密码
13.2.1.2.解释器模式的适用场景
1.一些重复出现的问题可以一种简单的语言来进行表达
2.一个简单的语法 需要解释的场景
13.2.2.解释器模式的通用实现
13.2.2.1.类图设计
13.2.2.2.代码实现
13.2.3.解释器模式实现案例之计算器功能
13.2.3.1.类图设计
13.2.3.2.代码实现
1.计算器功能
package com.wf.interpreter.demo.calculate; import java.util.Stack; /** * @ClassName Calculator * @Description 计算器 * @Author wf * @Date 2020/6/23 14:17 * @Version 1.0 */ public class Calculator { private Stack<IArithmeticInterpreter> stack = new Stack<>(); public Calculator(String expression) { parse(expression); } private void parse(String expression) { //解析 10 + 20 表达式 String[] eles = expression.split(" "); IArithmeticInterpreter left,right; for(int i= 0;i < eles.length;i++){ String operator = eles[i]; if(OperateUtil.ifOperator(operator)){ left =this.stack.pop(); right = new NumInterpreter(Integer.valueOf(eles[++i])); System.out.println("出栈:"+left.interpret()+"和"+right.interpret()); this.stack.push(OperateUtil.getInterpreter(left,right,operator)); System.out.println("应用运算符:"+operator); }else { NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(eles[i])); this.stack.push(numInterpreter); System.out.println("入栈:"+numInterpreter.interpret()); } } } public int calculate(){ return this.stack.pop().interpret(); } }
2.解释器顶层接口
package com.wf.interpreter.demo.calculate; /** * @ClassName IArithmeticInterpreter * @Description 顶层解释器接口 * @Author wf * @Date 2020/6/23 14:22 * @Version 1.0 */ public interface IArithmeticInterpreter { int interpret(); }
3.数值解释器实现
package com.wf.interpreter.demo.calculate; /** * @ClassName NumInterpreter * @Description 具体解释器实现类,终结表达式 * @Author wf * @Date 2020/6/23 14:24 * @Version 1.0 */ public class NumInterpreter implements IArithmeticInterpreter { private int value; public NumInterpreter(int value) { this.value = value; } @Override public int interpret() { return this.value; } }
4.两个操作数解释器抽象类
package com.wf.interpreter.demo.calculate; /** * @ClassName Interpreter * @Description 操作数解释器实现 * @Author wf * @Date 2020/6/23 14:26 * @Version 1.0 */ public abstract class Interpreter implements IArithmeticInterpreter { protected IArithmeticInterpreter left; protected IArithmeticInterpreter right; public Interpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { this.left = left; this.right = right; } //这里是一个空方法,具体逻辑在子类实现 @Override public int interpret() { return 0; } }
5.四则运算解释器实现
package com.wf.interpreter.demo.calculate; /** * @ClassName AddInterpreter * @Description +运算符解释器 * @Author wf * @Date 2020/6/23 14:29 * @Version 1.0 */ public class AddInterpreter extends Interpreter{ public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); } @Override public int interpret() { return this.left.interpret() + this.right.interpret(); } } package com.wf.interpreter.demo.calculate; /** * @ClassName SubInterpreter * @Description 减法解释器 * @Author wf * @Date 2020/6/23 14:29 * @Version 1.0 */ public class SubInterpreter extends Interpreter{ public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); } @Override public int interpret() { return this.left.interpret() - this.right.interpret(); } } package com.wf.interpreter.demo.calculate; /** * @ClassName MultiInterpreter * @Description 乘法解释器 * @Author wf * @Date 2020/6/23 14:31 * @Version 1.0 */ public class MultiInterpreter extends Interpreter { public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); } @Override public int interpret() { return this.left.interpret() * this.right.interpret(); } } package com.wf.interpreter.demo.calculate; /** * @ClassName DivInterpreter * @Description 除法解释器 * @Author wf * @Date 2020/6/23 14:29 * @Version 1.0 */ public class DivInterpreter extends Interpreter{ public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { super(left, right); } @Override public int interpret() { return this.left.interpret() / this.right.interpret(); } }
6.操作符工具类
package com.wf.interpreter.demo.calculate; /** * @ClassName OperateUtil * @Description 运算符解析工具类 * @Author wf * @Date 2020/6/23 14:43 * @Version 1.0 */ public class OperateUtil { public static boolean ifOperator(String symbol){ return (symbol.equals("+") || symbol.equals("-") || symbol.equals("*") || symbol.equals("/")); } public static Interpreter getInterpreter(IArithmeticInterpreter left,IArithmeticInterpreter right, String symbol){ if(symbol.equals("+")){ return new AddInterpreter(left,right); }else if(symbol.equals("-")){ return new SubInterpreter(left,right); }else if(symbol.equals("*")){ return new MultiInterpreter(left,right); }else if(symbol.equals("/")){ return new DivInterpreter(left,right); } return null; } }
7.测试类
package com.wf.interpreter.demo.calculate; /** * @ClassName Test * @Description 测试类 * @Author wf * @Date 2020/6/23 14:19 * @Version 1.0 */ public class Test { public static void main(String[] args) { System.out.println("result:"+new Calculator("10 + 30").calculate()); System.out.println("---------------------------"); System.out.println("result:"+new Calculator("10 * 30").calculate()); System.out.println("---------------------------"); System.out.println("result:"+new Calculator("10 - 30 + 11").calculate()); System.out.println("---------------------------"); System.out.println("result:"+new Calculator("10 / 30 + 10 * 4 - 15").calculate()); } }
测试结果:
其实,spring-expression模块中已经提供了四则运算的功能。
测试类如下:
package com.wf.interpreter.demo.calculate; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; /** * @ClassName SpringTest * @Description spring表达式包测试 * @Author wf * @Date 2020/6/23 15:34 * @Version 1.0 */ public class SpringTest { public static void main(String[] args) { ExpressionParser parser = new SpelExpressionParser(); Expression expression = parser.parseExpression("10 / 30 + 10 * 4 - 15"); Integer result = (Integer) expression.getValue(); System.out.println("计算结果:"+result);//25 } }
注意:这个代码是有问题的?
后面会进行分析并解决。如:10 * 30 + 10 * 4 - 15,表达式存在优先级问题,默认按从左到右的顺序执行。
添加依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.0.2.RELEASE</version> </dependency>
13.2.4.解释器模式在源码中应用
13.2.4.1.jdk下Pattern类
从构造器出发:
private Pattern(String p, int f) { pattern = p; //存储表达式 flags = f; // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present if ((flags & UNICODE_CHARACTER_CLASS) != 0) flags |= UNICODE_CASE; // Reset group index count capturingGroupCount = 1; localCount = 0; if (pattern.length() > 0) { compile(); //进行编译 } else { root = new Start(lastAccept); matchRoot = lastAccept; } }
13.2.4.2.spring中ExpressionParser
它是一个接口,下面查看实现类SpelExpressionParser:
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException { return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context); }
13.2.5.解释器模式的使用总结
13.2.5.1.优缺点总结
优点:
1.扩展性强:在解释器模式中,由于语法是由很多类表示,当语法规则更改时,只需要修改相应的非终结符表达式即可。
若扩展语法时,只需添加相应的非终结符类即可。
2.增加了新的解释表达式的方式。
3.易于实现文法:解释器模式对应的文法应当比较简单易于实现的,过于复杂的语法不适合使用解释器模式。
缺点:
1.语法规则比较复杂时,会引起类大量增加。
2.执行效率比较低。