【设计模式】中介者模式和观察者模式

news2025/3/1 22:31:06

中介者模式

中介模式的英⽂翻译是 Mediator Design Pattern。
在 GoF 中的《设计模式》⼀书中,它是这样定义的:

Mediator pattern defines a separate (mediator) object that encapsulates the interaction between a set of objects and the objects delegate their interaction to a mediator object instead of interacting with each other directly.

中介模式定义了⼀个单独的(中介)对象,来封装⼀组对象之间的交互。将这组对象之间的交互委派给中介对象,来避免对象之间的直接交互。属于行为型模式

通过引⼊中介这个中间层,将⼀组对象之间的交互关系(或者说依赖关系)从多对多(⽹状关系)转换为⼀对多(星状关系)

我们的注册中心就是中介者模式的典型应用场景,比方说朋友圈,QQ群, 淘宝商城都是中介者模式在生活上的应用

中介者模式主要有四个角色:
Mediator: 抽象中介者
ConcreteMediator: 具体中介者
Colleague: 抽象同事类
ConcreteColleague: 具体同事类

在一些简单场景下,可以不设计抽象中介者和抽象同事类,具体看你的使用场景

代码示例

我们用代码实现下QQ群的场景,每个QQ号都可以在群里发送内容,QQ群就承担着一个中介者的作用

public class QQ {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public QQ(String name) {
        this.name = name;
    }

    public void sendMessage(QQGroup qqGroup, String message) {
        if (qqGroup.getMembers().contains(this)) {
            System.out.println("[" + this.name + "]:" + message + "in qq group " + qqGroup.getName());
        } else {
            System.err.println("你不在群里,不能说话");
        }
    }
}

public class QQGroup {
    private List<QQ> members;
    private String name;

    public List<QQ> getMembers() {
        return members;
    }

    public void addMember(QQ qq) {
        if (members == null) {
            members = new ArrayList<>();
        }
        members.add(qq);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Test {

    public static void main(String[] args) {
        QQ member1 = new QQ("小明");
        QQ member2 = new QQ("小一");
        QQ member3 = new QQ("小花");
        QQGroup group = new QQGroup();
        group.setName("私人聊天群");
        group.addMember(member1);
        group.addMember(member2);
        member1.sendMessage(group, "明天我们去逛街");
        member2.sendMessage(group, "好啊");
        member3.sendMessage(group, "我也去");

    }

}

在这里插入图片描述

观察者模式

观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。
在 GoF 的《设计模式》⼀书中,它的定义是这样的:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

在对象之间定义⼀个⼀对多的依赖,当⼀个对象状态改变的时候,所有依赖的对象都会⾃动收到通知。属于行为型模式。

⼀般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。不过,在实际的项⽬开发中,这两种对象的称呼是⽐较灵活的,有各种不同的叫法,⽐如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener等。

观察者模式主要包含4种角色
抽象被观察者(Subject):被观察的对象,被观察者提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
具体被观察者
:在被观察者内部状态改变时,给所有注册过的观察者发出通知。
抽象观察者:为所有具体的观察者定义一个响应通知的接口
具体观察者:实现抽象观察者角色所要求的更新接口

代码示例

public class MyObservable {

    List<MyObserver> observerList;

    public void addObserver(MyObserver observer) {
        if (observerList == null) {
            observerList = new ArrayList<>();
        }
        observerList.add(observer);
    }

    public void notifyAllObserver(Object arg) {
        if (observerList == null) {
            return;
        }
        for (MyObserver observer : observerList) {
            observer.update(this, arg);
        }
    }

}

public class OrderCompleted extends MyObservable {

    private Long orderId;

    public OrderCompleted(Long orderId) {
        this.orderId = orderId;
    }

    public void notifyObservers() {
        //如果是使用的jdk自带的Observable类,要先设置changed标识,后续才可以发送成功
        super.notifyAllObserver(orderId);
    }
}

public interface MyObserver {

    void update(MyObservable observable, Object arg);
}

public class SmsNotification implements MyObserver {

    @Override
    public void update(MyObservable o, Object arg) {
        Long orderId = (Long) arg;
        System.out.println("您已下单成功,订单号为:" + orderId);
    }
}

public class EmailNotification implements MyObserver {

    @Override
    public void update(MyObservable o, Object arg) {
        Long orderId = (Long) arg;
        System.out.println("您已下单成功,升级为白金用户,订单号为:" + orderId);
    }
}

public class Test {
    
    public static void main(String[] args) {
        OrderCompleted orderCompleted = new OrderCompleted(9888121L);
        SmsNotification sms = new SmsNotification();
        EmailNotification email = new EmailNotification();
        orderCompleted.addObserver(sms);
        orderCompleted.addObserver(email);
        orderCompleted.notifyObservers();
    }
}

在这里插入图片描述

中介者模式和观察者模式对比

观察者模式和中介模式都是为了实现参与者之间的解耦,简化交互关系。
两者的不同在于应⽤场景上。在观察者模式的应⽤场景中,参与者之间的交互⽐较有条理,⼀般都是单向的,⼀个参与者只有⼀个⾝份,要么是观察者,要么是被观察者。
⽽在中介模式的应⽤场景中,参与者之间的交互关系错综复杂,既可以是消息的发送者、也可以同时是消息的接收者。

中介者模式和代理模式对比:
代理模式重点在代理,会对原对象做功能增强;但是中介者模式就是一个转发的作用,实际的工作还是要你自己去完成

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

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

相关文章

C#:Krypton控件使用方法详解(第十五讲) ——kryptonBorderEdge

今天介绍的Krypton控件中的kryptonBorderEdge。下面介绍控件的外观属性如下图所示&#xff1a;Cursor属性&#xff1a;表示鼠标移动过该控件的时候&#xff0c;鼠标显示的形状。属性值如下图所示&#xff1a;UseWaitCursor属性&#xff1a;表示鼠标在控件中等待时&#xff0c;以…

大学模拟电路期末考试模拟题详解

&#xff08;一&#xff09;选择题 3.4.5.6.7.8.9.10. &#xff08;二&#xff09;填空题 1.漂流电流是温度电流&#xff0c;它由少数、载流子形成、其大小与温度有关&#xff0c;而与外加电压无关。 反向电流是由少数载流子形成、其大小与温度有关&#xff0c;而与外加电压无…

AOP通知类型:

AOP通知类型&#xff1a; 环绕通知无参与ProceedingJoinPoint接口&#xff1a;方法的前后进行环绕&#xff0c;但是与before和after不同的是&#xff0c;他无法知道下面代码中的环绕前方法是否是在前置位置&#xff0c;后置同理&#xff0c;于是要在方法中添加参数ProceedingJo…

Android之事件机制

Android之事件机制MotionEvent事件的分发与处理触屏事件的类型触摸事件发生的位置触摸事件的分发和处理用于分发和处理的方法事件分发和处理的过程KeyEvent参考MotionEvent事件的分发与处理 在我们日常使用app的时候会进行各种各样的触摸操作&#xff0c;比如点击、长按等&…

谈一谈搜索引擎是如何跟踪你、出卖你的

文章目录跟踪结果点击跟踪关键词跟踪other跟踪 结果点击跟踪 以b网为例&#xff0c;当我们搜索关键词“haha”后&#xff0c;搜索结果链接是这样子的&#xff1a; https://www.baidu.com/link?urlX02KNEaEhaHM-7eY_i6OWGWBZ9_KEYvIlMec91jStRWvcg4uyumrhdefe-ZzdrLKk7iewh9a…

pycharm专业版安装_教育邮箱

怎样安装pycharm专业版&#xff1f; 专业版与社区版的区别 二者区别很多&#xff0c;笔者主要看中了远程连接这个功能。下面讲解怎样使用教育邮箱免费获取专业版pcharm。 1.获取免费的利license &#xff08;1&#xff09;进入pycharm官方网站&#xff0c;链接为&#xff1…

小米数据恢复:有无备份从小米手机恢复删除数据方法

如果您不小心删除了小米手机上的数据&#xff0c;后来发现您需要它&#xff0c;那么本文适合您。我将向您介绍一些最可靠的小米恢复方法&#xff0c;以将您的数据恢复到您的设备上。无论您是否有备份&#xff0c;都可以处理。让我们开始吧&#xff01; 小米数据恢复 - 如何做&a…

vue打包后用docker镜像部署

vue3项目打包成dist后&#xff0c;用Dockerfile&#xff0c;镜像部署。后在线上运行。 我在阿里云买了个轻量服务器。系统镜像是centos7。现在Linux下安装Docker。 比如我打包好的dist文件夹&#xff0c;要和Dockorfile在同一级目录下&#xff0c;不然在build构建时是找不到d…

第十届省赛——9等差数列(集合做法)

题目&#xff1a;试题 I: 等差数列时间限制: 1.0s 内存限制: 512.0MB 本题总分&#xff1a;25 分【问题描述】数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列&#xff0c;只记得其中 N 个整数。现在给出这 N 个整数&#xff0c;小明想知道包含这…

推荐系统中对抗性机器学习-文献综述与未来发展整理分享

对抗学习是一种机器学习技术&#xff0c;旨在通过提供欺骗性输入来欺骗模型。最常见的原因是导致机器学习模型出现故障。大多数机器学习技术旨在处理特定的问题集&#xff0c;其中从相同的统计分布&#xff08;IID&#xff09;生成训练和测试数据。当这些模型应用于现实世界时&…

【数据库】聊聊MySQL的日志,binlog、undo log、redo log

日志 在数据库中&#xff0c;如何保证数据的回滚&#xff0c;以及数据同步&#xff0c;系统宕机后可以恢复到原来的状态&#xff0c;其实就是依靠日志。 其中bin log是Server层特有的&#xff0c;redo log是Innodb存储引擎特有的。 bin log 是逻辑日志&#xff0c;主要记录这条…

Win11安装Docker

一、进入Docker官网首先先到Docker官网下载最新官方Docker for Windows链接&#xff1a;Docker下载在官网内可以查看到Docker的开发文档&#xff1a;根据官网提示&#xff0c;Windows环境下下载Docker必须满足&#xff1a;Docker for Windows requires 64bit Windows 11 Pro an…

0311记录

题目1&#xff1a;B. Not Dividing 这个题有点奇怪&#xff0c;他的大意就是给定一个数组&#xff0c;可以对数组中的任意一个数做&#xff0b;1操作&#xff0c;保证a(i1)不被a(i)整除&#xff0c;但是总次数不能超过2*n 感觉这就是一个结论吧&#xff0c;就是随便加&#xff…

CSS看这一篇就够啦,CSS基础大全,可用于快速回顾知识,面试首选

1 CSS简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称。 CSS 是也是一种标记语言&#xff0c;主要用于设置 HTML 页面中的文本内容&#xff08;字体、大小、对齐方式等&#xff09;、图片的外形&#xff08;宽高、边框样式、 边距等&#xff09;以及版面的布局和外观…

【Linux】linux | 修改系统编码 |  增加字体处理 | 图片处理字体变成方块

一、说明1、CentOS7二、修改系统编码编辑文件vi /etc/locale.conf修改编码并保存LANGzh_CN.UTF-8配置生效source /etc/locale.conf1&#xff09;修改系统编码&#xff0c;只是让系统支持中文编码2&#xff09;不解决文字不显示的问题&#xff1b;往后看三、解决字体不显示问题非…

【玩转c++】priority_queue的介绍和模拟实现

本期主题&#xff1a;priority_queue的介绍和模拟实现博客主页&#xff1a; 小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐priority_queue介绍和使用1.1.priority_queue介绍1. 优先队列是一种容器适配器&#xff0c;根…

数组边遍历(for循环)边删除为什么删不干净 及三种实现删除的方法

文章目录1、为什么删不干净倒序删迭代器lambda表达式删除为什么说数组边for循环遍历边删除会出现删不干净的情况1、为什么删不干净 先写一个例子&#xff1a;可以先猜一下控制台会打印出什么内容&#xff1f; public class removeIterator {public static void main(String[]…

Node.js 里 Express工程框架中的代码解析

新建一个工程 express -e blog配置入口文件 打开项目内的app.js ,在倒数第二行写入如下代码&#xff1a; app.listen(3000, function () {console.log(server is running in 3000) })这样就让服务运行在了3000端口 检查 打开终端输入&#xff1a; node app在打开浏览器访…

client-go实战之十:标签选择(labels.Selector),重要

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 系列文章链接 client-go实战之一&#xff1a;准备工作client-go实战之二:RESTClientclient-go实战之三&#xff1a;Clientsetclient-go实战之四&#xff1a;…

智能优化算法求解CEC2005中F1-F25的种群动态变化图(视频)

CEC2005 测试集共包含 25 个测试问题, 即 f1−f25f_{1}-f_{25}f1​−f25​ 。根据问题的特征, 可进一 步将其分为 4 类: 单峰问题 f1−f5f_{1}-f_{5}f1​−f5​ , 基本多峰问题 f6−f12f_{6}-f_{12}f6​−f12​ , 扩展多峰问题 f13−f14f_{13}-f_{14}f13​−f14​ 和混合复合问…