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

news2024/9/24 15:24:05

目录

  • 1 中介模式详解
    • 1.1 中介模式的定义
      • 1.1.1 中介者模式在生活场景中应用
      • 1.1.2 中介者模式的使用场景
    • 1.2 中介模式的通用实现
      • 1.2.1 类图设计
      • 1.2.2 代码实现
    • 1.3 中介模式应用案例之聊天室
      • 1.3.1 类图设计
      • 1.3.2 代码实现
    • 1.4 中介者模式在源码中应用
      • 1.4.1 jdk中Timer类
    • 1.5 中介者模式使用总结
      • 1.5.1 优缺点总结
      • 1.5.2 与其他模式的关系总结
  • 2 解释器模式详解
    • 2.1 解释器模式的定义
      • 2.1.1 解释器模式在生活场景中应用
      • 2.1.2 解释器模式的适用场景
    • 2.2 解释器模式的通用实现
      • 2.2.1 类图设计
      • 2.2.2 代码实现
    • 2.3 解释器模式实现案例之计算器功能
      • 2.3.1 类图设计
      • 2.3.2 代码实现
      • 2.3.3 解释器模式在源码中应用
      • 2.4.4 spring中ExpressionParser
    • 2.5 解释器模式的使用总结
      • 2.5.1 优缺点总结


1 中介模式详解

1.1 中介模式的定义

定义:

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

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

核心:

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

属于行为型模式。

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

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

中介者就很方便了。

2.朋友圈。

3.数据整合中心

4.rpc通信

1.1.2 中介者模式的使用场景

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

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

1.2 中介模式的通用实现

1.2.1 类图设计

img

1.2.2 代码实现

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

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

1.3.1 类图设计

img

说明:

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

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()+"欢迎大家,进入聊天室");
    }
}

测试结果:

img

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 类图设计

img

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());
    }
}

测试结果:

img

其实,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 = 1;
        localCount = 0;

        if (pattern.length() > 0) {
            compile();  //进行编译
        } else {
            root = new Start(lastAccept);
            matchRoot = lastAccept;
        }
    }

2.4.4 spring中ExpressionParser

img

它是一个接口,下面查看实现类SpelExpressionParser:

protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
   return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
}

2.5 解释器模式的使用总结

2.5.1 优缺点总结

优点:

1.扩展性强:在解释器模式中,由于语法是由很多类表示,当语法规则更改时,只需要修改相应的非终结符表达式即可。

若扩展语法时,只需添加相应的非终结符类即可。

2.增加了新的解释表达式的方式。

3.易于实现文法:解释器模式对应的文法应当比较简单易于实现的,过于复杂的语法不适合使用解释器模式。

缺点:

1.语法规则比较复杂时,会引起类大量增加。

2.执行效率比较低。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/356636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

logd守护进程

logd守护进程1、adb logcat命令2、logd守护进程启动2.1 logd文件目录2.2 main方法启动3、LogBuffer缓存大小3.1 缓存大小优先级设置3.2 缓存大小相关代码位置android12-release1、adb logcat命令 命令功能adb bugreport > bugreport.txtbugreport 日志adb shell dmesg >…

kafka-11-kafka的监控工具和常用配置参数

kafka官方文档 参考Kafka三款监控工具比较 1 查看kafka的版本 进入kafka所在目录&#xff0c;通过查看libs目录下的jar包。 2.11是scala的版本&#xff0c;2.0.0是kafka的版本。 测试环境 #systemctl start zookeeper #systemctl start kafkka 2 kafka的常用配置 Kafka使用…

SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】

SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】 目录SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】一、创建一个SpringBoot项目二、修改pom.xml中SpringBoot的版本三、配置文件3.1 application-dev.ym…

2.TCP/UDP什么时候选择,HTTP,使用TCP/UDP的协议有哪些,TCP三次握手四次挥手大概流程,为什么要三次握手.

文章目录1.什么时候选择 TCP,什么时候选 UDP?2. HTTP 基于 TCP 还是 UDP&#xff1f;3.使用 TCP 的协议有哪些?使用 UDP 的协议有哪些?4.TCP 三次握手和四次挥手&#xff08;非常重要、传输层&#xff09;5.为什么要三次握手?1.什么时候选择 TCP,什么时候选 UDP? UDP 一般…

Spring Cloud Nacos实战(五)- 命名空间分组和DataID三者关系

Nacos命名空间分组和DataID三者关系 名词解释 命名空间&#xff08;Namespace&#xff09; ​ 用于进行租户粒度的配置隔离。不同的命名空间下&#xff0c;可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离&#xff0c;例如开发…

Kubernetes一 Kubernetes之入门

二 Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应…

机器学习实战教程(六):决策树

决策树 决策树是什么&#xff1f;决策树(decision tree)是一种基本的分类与回归方法。举个通俗易懂的例子&#xff0c;如下图所示的流程图就是一个决策树&#xff0c;长方形代表判断模块(decision block)&#xff0c;椭圆形成代表终止模块(terminating block)&#xff0c;表示…

SpringBoot实战——个人博客项目

目录 一、项目简介 二、项目整体架构 数据库模块 后端模块 前端模块 三、项目具体展示 四、项目的具体实现 1、一些准备工作 &#x1f34e;数据库、数据表的创建 &#x1f34e;设置数据库和MyBatis的配置 &#x1f34e;将前端项目引入到当前项目中 2、登录注册模块 &…

CV学习笔记-Inception

CV学习笔记-Inception 目录 文章目录CV学习笔记-Inception目录1. 常见的卷积神经网络2. Inception(1) Inception提出背景(2) Inception module 核心思想3. Inception的历史版本(1) InceptionV1-GoogleNet(2) InceptionV2(3) InceptionV3(4) Inception V44. Inception模型的特点…

一起学 pixijs(4):如何绘制文字md

大家好&#xff0c;我是前端西瓜哥&#xff0c;今天我们来学 pixijs 如何绘制文字。pixijs 版本为 7.1.2。 使用原生的 WebGL 来绘制文字是非常繁琐的&#xff0c;pixijs 对此进行了高层级的封装&#xff0c;提供了 Text 类和 BitMapText 类来绘制文字。 Text 最基本的写法&…

【Flutter入门到进阶】Dart进阶篇---Dart异步编程

1 并行与并发的编程区别 1.1 并发与并行 1.1.1 说明 我们举个例子,如果有条高速公路 A 上面并排有 8 条车道,那么最大的并行车辆就是 8 辆此条高速公路 A 同时并排行走的车辆小于等于 8 辆的时候,车辆就可以并行运行。 CPU 也是这个原理,一个 CPU 相当于一个高速公路 A,核心数…

Ubuntu20.04如何安装虚拟机(并安装Android)

安装虚拟机&#xff08;KVM&#xff09;这种KVM只能安装windows无法安装安卓(From https://phoenixnap.com/kb/ubuntu-install-kvm)A type 2 hypervisor enables users to run isolated instances of other operating systems inside a host system. As a Linux based OS, Ubun…

Redis第四讲

目录 四、Redis04 4.1 Redis集群应用场景 4.2 集群 4.2.1 基本原理 4.2.2 主从复制的作用 4.3 配置集群&#xff08;一台虚拟机&#xff09; 4.3.1 规划网络 4.3.2 创建节点 4.3.3 创建目录 4.3.4 配置redis7001.conf 4.3.5 配置其余文件 4.3.6 后台启动redis 4.3…

【NLP实战】NLTK工具包

“Natural Language Toolkit&#xff0c;自然语言处理工具包&#xff0c;在NLP领域中&#xff0c;最常使用的一个Python库。NLTK是一个开源的项目&#xff0c;包含&#xff1a;Python模块&#xff0c;数据集和教程&#xff0c;用于NLP的研究和开发。NLTK由Steven Bird和Edward …

「可信计算」助力TLS 传输更安全

序言背景&#xff08;Satuation&#xff09;&#xff1a;TLS 是 TCP/IP 上的传输层安全协议&#xff0c;保护着数以亿万级的数据安全&#xff0c;我们在浏览器中输入的 https&#xff0c;就是受到 TLS 保护的。冲突&#xff08;complication&#xff09;&#xff1a;从可信计算…

洛谷P8601[蓝桥杯][2013年第四届真题]剪格子

题目描述如图 11 所示&#xff0c;33 的格子中填写了一些整数。我们沿着图中的红色线剪开&#xff0c;得到两个部分&#xff0c;每个部分的数字和都是 6060。本题的要求就是请你编程判定&#xff1a;对给定的 m\times nmn 的格子中的整数&#xff0c;是否可以分割为两个部分&am…

【Java开发】Spring 12 :Spring IOC控制反转和依赖注入(解决单接口多实现类调用)

IOC 是 Inversion of Control 的简写&#xff0c;译为“控制反转”&#xff0c;Spring 通过 IOC 容器来管理所有 Java 对象的实例化和初始化&#xff0c;控制对象与对象之间的依赖关系。我们将由 IOC 容器管理的 Java 对象称为 Spring Bean&#xff0c;它与使用关键字 new 创建…

分享112个HTML艺术时尚模板,总有一款适合您

分享112个HTML艺术时尚模板&#xff0c;总有一款适合您 112个HTML艺术时尚模板下载链接&#xff1a;https://pan.baidu.com/s/1D3-mfPOud-f3vy9yLl-bmw?pwdfph2 提取码&#xff1a;fph2 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 时尚平面模特网站模板 潮…

Redis数据类型以及应用场景

目录1、 String&#xff08;字符串&#xff09;2、 Hash&#xff08;哈希&#xff09;3、 List&#xff08;列表&#xff09;4、 Set&#xff08;集合&#xff09;5、 sorted set&#xff08;有序集合ZSet&#xff09;字符串&#xff08;String&#xff09;、哈希表&#xff08…

40/365 javascript 严格检查模式 字符串

1.严格检查模式 因为js语法的随意性&#xff0c;可以直接使用变量&#xff08;没有声明&#xff09;&#xff0c;也不会报错。 <script>n 5;</script> 但这样会造成很多问题&#xff0c;一是变量不声明就使用&#xff0c;二是这样使用的变量会是全局变量&#x…