设计模式之中介模式与解释器模式详解和应用

Posted 赵广陆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之中介模式与解释器模式详解和应用相关的知识,希望对你有一定的参考价值。

目录


1 中介模式详解

1.1 中介模式的定义

定义:

中介者模式【Mediator Pattern】,又称调解者模式或调停者模式。用一个中介对象封装一系列的对象

交互,中介者使用各对象不需要显式地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

核心:

通过中介者解耦系统各层次对象的直接耦合,层次对象的对外依赖通信统统交由中介者转发。

属于行为型模式。

1.1.1 中介者模式在生活场景中应用

1.人际交往圈,通讯网络。如果需要自己逐个去建立关系会很困难且复杂,如果加入中介者,来维护这个网络。

中介者就很方便了。

2.朋友圈。

3.数据整合中心

4.rpc通信

1.1.2 中介者模式的使用场景

1.系统中对象之间存在复杂的引用关系,产生相互依赖关系结构混乱且难以理解。

2.交互的公共行为,如果需要改变行为则可以增加新的中介者类。

1.2 中介模式的通用实现

1.2.1 类图设计

1.2.2 代码实现

1.3 中介模式应用案例之聊天室

很多人进入一个聊天室,或聊天群里,群或聊天室,都充当中介者的角色。

1.3.1 类图设计

说明:

这里通过用户名,表示不同用户。

1.3.2 代码实现

1.中介者【聊天室】

package com.oldlu.mediator.demo.chatroom;

/**
 * @ClassName ChatRoom
 * @Description 聊天室
 * @Author oldlu
 * @Version 1.0
 */
public class ChatRoom 
    public void showMsg(User user,String message)
        System.out.println("【"+user.getName() +"】,传达信息:"+message);
    

它就只是一个传话者,把信息发布者的内容,传达出来。

2.用户类【聊天者】

package com.oldlu.mediator.demo.chatroom;

/**
 * @ClassName User
 * @Description 用户类
 * @Author oldlu
 * @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.oldlu.mediator.demo.chatroom;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author oldlu
 * @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()+"欢迎大家,进入聊天室");
    

测试结果:

1.4 中介者模式在源码中应用

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充当中介者的角色。

1.5 中介者模式使用总结

1.5.1 优缺点总结

优点:

1.减少类间依赖,将多对多依赖关系,转化成一对多的关系,降低了类间的耦合性。

2.类间各司其职,符合迪米特法则。

缺点:

中介者模式,将原本多个对象直接的相互依赖关系,变成依赖中介者和多个同事类的依赖关系。

当同事类越来越多时,中介者责任越来越大,且复杂难以维护。

1.5.2 与其他模式的关系总结

中介者模式和代理模式的区别:

1.都存在中间角色。

2.代理模式,着重在代理【增强功能】

3.中介者模式,只他帮你联系上了,就不管了,后面的事情全权由自己完成。【只管搭桥】

2 解释器模式详解

2.1 解释器模式的定义

定义:

解释器模式【Interpretor Pattern】给定一个语言,定义它的文法的一种表示,并定义解释器。

这个解释器使用该表示来解释语言中的句子

特征:

为了解释一种语言,而为语言创建的解释器。

属于行为型模式。

2.1.1 解释器模式在生活场景中应用

1.音乐简谱

2.摩斯密码

2.1.2 解释器模式的适用场景

1.一些重复出现的问题可以一种简单的语言来进行表达

2.一个简单的语法 需要解释的场景

2.2 解释器模式的通用实现

2.2.1 类图设计

2.2.2 代码实现

2.3 解释器模式实现案例之计算器功能

2.3.1 类图设计

2.3.2 代码实现

1.计算器功能

package com.oldlu.interpreter.demo.calculate;

import java.util.Stack;
/**
 * @ClassName Calculator
 * @Description 计算器
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName IArithmeticInterpreter
 * @Description 顶层解释器接口
 * @Author oldlu
 * @Version 1.0
 */
public interface IArithmeticInterpreter 
    int interpret();

3.数值解释器实现

package com.oldlu.interpreter.demo.calculate;

/**
 * @ClassName NumInterpreter
 * @Description 具体解释器实现类,终结表达式
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName Interpreter
 * @Description 操作数解释器实现
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName AddInterpreter
 * @Description +运算符解释器
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName SubInterpreter
 * @Description 减法解释器
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName MultiInterpreter
 * @Description 乘法解释器
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName DivInterpreter
 * @Description 除法解释器
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName OperateUtil
 * @Description 运算符解析工具类
 * @Author oldlu
 * @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.oldlu.interpreter.demo.calculate;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author oldlu
 * @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.oldlu.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 oldlu
 * @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>

2.3.3 解释器模式在源码中应用

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 = 1GoF 23 种设计模式之中介者模式和解释器模式

设计模式之代理模式(Proxy)详解及代码示例

c#面向对象10--简单工厂设计模式

Java开发中的23种设计模式详解之三:11种行为型模式

Java 设计模式之中介者学习与掌握

Java 设计模式之中介者学习与掌握