zoukankan      html  css  js  c++  java
  • 设计模式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.执行效率比较低。

  • 相关阅读:
    [你必须知道的.NET]第三十四回,object成员,不见了!
    [你必须知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>点滴
    [你必须知道的.NET]第三十二回,,深入.NET 4.0之,Tuple一二
    [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望
    C#中String跟string的“区别”
    [你必须知道的.NET]第三十回:.NET十年(下)
    log4j.properties 详解与配置步骤
    Linux下进程数量的限制pid_max的配置方法
    解决OutOfMemoryError: unable to create new native thread问题
    ORA-12518: TNS:listener could not hand off client connection
  • 原文地址:https://www.cnblogs.com/wfdespace/p/13182942.html
Copyright © 2011-2022 走看看