【再探】设计模式—中介者模式、观察者模式及模板方法模式

news2025/1/23 6:09:17

 中介者模式让多对多的复杂引用关系变成一对多,同时能通过中间类来封装多个类中的行为,观察者模式在目标状态更新时能自动通知给订阅者,模版方法模式则是控制方法的执行顺序,子类在不改变算法的结构基础上可以扩展功能实现。

1 中介者模式

需求:1)系统中对象之间存在复杂的引用关系,比如一对多,多对多等。系统结构耦合度很高,结构混乱且难以理解。2)想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。在中间类中定义对象交互的公共行为。

1.1 中介者模式介绍

用一个中介对象来封装一系列的对象交互。使得各个对象不需要显式地相互引用,从而使其耦合度松散,而且可以独立地改变它们之间的交互。

图 中介者模式 UML

需求描述:在前端开发中,有三个组件 Button、View, 及Text. View 用来展示信息,Text 用于输入编辑信息,Button用来提交更新。用户在Text输入好内容后,点击Button后,内容会更新到View. 而点击View时,会把内容输入到Text。

图 需求分析图

图 需求分析UML

public class NoMediatorPattern {

    public static void main(String[] args) {
        Text text = new Text();
        Button button = new Button();
        View view = new View();

        button.setText(text);
        button.setView(view);
        view.setText(text);

        button.click();
        view.click();
        button.click();
    }

    private static class Button {

        private Text text;
        private View view;

        public void setText(Text text) {
            this.text = text;
        }

        public void setView(View view) {
            this.view = view;
        }

        void click() {
            if (text != null && view != null) {
                view.onRefresh(text.generateText());
            }
        }
    }

    private static class Text  {

        private String content;

        private String generateText() {
            if (content == null) content = "";
            Random random = new Random();
            content += random.nextInt();
            return content;
        }

        void onRefresh(String text) {
            content = text;
        }
    }

    private static class View{

        private Text text;

        private String content;

        public void setText(Text text) {
            this.text = text;
        }

        void click() {
            if (text != null) {
                text.onRefresh(content);
            }
        }

        void onRefresh(String text) {
            this.content = text; // 更新信息
            System.out.println("View中显示信息:" + text);
        }
    }

}

上面代码中,需要考虑Button 与 Text、View,View 与Text 的交互。这使得系统逻辑变得更复杂。

图 中介者模式思维下的需求分析

图 中介者模式思维下的 UML

中介者模式下,只需要考虑中介者与各同事类的交互。

public class MediatorPattern {

    public static void main(String[] args) {

        Mediator mediator = new ContentMediator();

        Component text = new Text(mediator, "text");
        Component button = new Button(mediator,"button");
        Component view = new View(mediator,"view");

        mediator.registry(text);
        mediator.registry(button);
        mediator.registry(view);

        button.onClick();
        button.onClick();
        view.onClick();
        button.onClick();
    }

    private static abstract class Mediator {

        protected final Set<Component> components = new HashSet<>();

        public void registry(Component component) {
            if (component != null) {
                components.add(component);
            }
        }

        abstract void update(String content,String target);

    }

    private static class ContentMediator extends Mediator{

        @Override
        public void update(String content,String target) {
            if (content == null) {
                Text text = getText();
                if (text == null) throw new RuntimeException("没有更新内容");
                content = text.getContent();
            }
            for (Component component : components) {
                if (component.getTag().equals(target)) {
                    component.onRefresh(content);
                }
            }
        }

        private Text getText() {
            for (Component component : components) {
                if ("text".equals(component.getTag())) return (Text) component;
            }
            return null;
        }
    }

    private static abstract class Component {
        protected final Mediator mediator;
        private final String tag;

        protected Component(Mediator mediator, String tag) {
            this.mediator = mediator;
            this.tag = tag;
        }

        public String getTag() {
            return tag;
        }

        abstract void onClick();

        abstract void onRefresh(String content);
    }

    private static class Text extends Component {

        private String content;

        protected Text(Mediator mediator, String tag) {
            super(mediator, tag);
        }

        @Override
        void onClick() { // 输入操作
            throw new RuntimeException("暂不支持Text的点击事件");
        }

        @Override
        void onRefresh(String content) {
            this.content = content;
        }

        public String getContent() {
            Random random = new Random();
            String temp = content;
            if (temp == null) temp = "";
            temp += random.nextInt() + "@";
            content = null;
            return temp;
        }
    }

    private static class View extends Component {

        private String content;

        protected View(Mediator mediator, String tag) {
            super(mediator, tag);
        }

        @Override
        void onClick() {
            mediator.update(content,"text");
        }

        @Override
        void onRefresh(String content) {
            this.content = content;
            System.out.println("view更新:"+ content);
        }
    }

    private static class Button extends Component {

        protected Button(Mediator mediator, String tag) {
            super(mediator, tag);
        }

        @Override
        void onClick() {
            mediator.update(null,"view");
        }

        @Override
        void onRefresh(String content) {
            throw new RuntimeException("暂不支持Button的更新操作");
        }
    }

}

1.2 优缺点

优点:

  1. 简化了对象之间的交互,将原本多对多的交互改成一对多。使得对象之间解耦。
  2. 可以通过中介者类来扩展对象的交互行为,当需要添加或改变交互行为时,只需要添加对应的中介者子类即可,符合开闭原则。
  3. 同事类可以更专注自身业务,而不必关心与其他同事类的交互。

缺点:

  1. 中介者类包含同事类之间大量的交互细节,使得该类变得非常复杂,不符合单一职责原则。
  2. 中介者类与同事类的耦合度高。

2 观察者模式

需求:当目标更新时,能自动通知给订阅者。

2.1 观察者模式介绍

当目标对象的状态发生改变时,它的所有观察者都会收到通知。

图 观察者模式 UML

public class ObserverPattern {

    public static void main(String[] args) {
        Subject subject = new School();

        Observer observer1 = new Teacher();
        Observer observer2 = new Student();
        subject.attach(observer1);
        subject.attach(observer2);

        subject.notifyObserverList("快高考啦!");
        subject.notifyObserverList("六一放假");
    }

    private static abstract class Subject {
        protected final Set<Observer> observerList = new HashSet<>();

        public void attach(Observer observer) {
            observerList.add(observer);
        }

        public void detach(Observer observer) {
            observerList.remove(observer);
        }

        public void notifyObserverList(String content) {
            beforeNotify(content);
            for (Observer observer : observerList) observer.update(content);
            afterNotify(content);
        }

        public abstract void beforeNotify(String content);

        public abstract void afterNotify(String content);

    }

    private static class School extends Subject {

        @Override
        public void beforeNotify(String content) {
            System.out.println("通知时间:" + new Date());
        }

        @Override
        public void afterNotify(String content) {
            System.out.println("通知完成");
        }
    }

    private interface Observer {
        void update(String content);
    }

    private static class Student implements Observer {
        @Override
        public void update(String content) {
            if (content.contains("放假")) System.out.println("学生,耶耶耶!");
            else System.out.println("学生,哦哦哦");
        }
    }

    private static class Teacher implements Observer {

        @Override
        public void update(String content) {
            System.out.println("老师,收到:" + content);
        }
    }

}

2.2 优缺点

优点:

  1. 当目标状态更新时,能自动发生通知给订阅者。
  2. 观察者与被观察者耦合度低,符合依赖倒置原则。

缺点:

  1. 当观察者数量较多时,通知耗时会加长。一个观察者的卡顿会影响整体执行效率

3 模版方法模式

需求:对方法的执行顺序有要求,而某些特定方法由子类去实现。例如想写排序算法,算法内部中方法的执行顺序相同,但具体排序算法由不同子类实现。

3.1 模版方法模式介绍

定义一个操作中的算法框架,将一些步骤延迟到子类中,子类在不改变算法的结构基础上重定义该算法的某些特定步骤。

图 模版方法模式 UML

public class TemplateMethodPattern {

    public static void main(String[] args) {
        Worker programmer = new Programmer();
        programmer.work();
    }

    private static abstract class Worker {

        public void work() {
            punch("上班");
            duty();
            punch("下班");
        }

        protected abstract void duty();

        protected void punch(String content) {
            System.out.println("打卡:" + content);
        }
    }

    private static class Programmer extends Worker {

        @Override
        protected void duty() {
            System.out.println("写bug AND 解决bug");
        }
    }

}

3.2 优缺点

优点:

  1. 可以控制方法执行顺序,当要增加新的方法实现时,只需要添加特定子类。符合开闭原则及里氏替换原则。

缺点:

  1. 增加了类的个数。

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

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

相关文章

ESP8266使用AT指令登陆新版OneNET平台进行固定数据上报

登陆OneNET进开发者中心 创建产品 创建云平台产品 产品类别和智能化方式选择 产品名称和城市自定义选择&#xff0c;框选部分参照下图&#xff0c;开发方案选标准方案时平台会预置标准物模型和App控制面板&#xff0c;选自定义方案用户可自行定义物模型和App控制面板&…

RedisTemplate实战应用--队列等

一、RedisTemplate队列插入 1、从集合左边插入值 https://blog.csdn.net/weixin_43658899/article/details/121040307 leftPush(K key, V value) redisTemplate.opsForList().leftPush("leftdatakey","bbbb");2、从集合左边开始在v1值后边插入新值v2 le…

忘记论文Word文档密码,如何找回加密密码

论文的撰写与保存是每位学者都需面对的重要任务。为了保护自己的劳动成果&#xff0c;许多学者会选择对Word文档进行加密&#xff0c;设置密码以确保文档的安全。然而&#xff0c;有时我们可能会因为各种原因忘记了文档密码&#xff0c;这无疑会给我们的工作带来诸多不便。那么…

跨境电商如何有效做好店铺账号管理?

跨境电商有效做好店铺账号管理至关重要&#xff0c;类似亚马逊、Temu、TikTok、ebay跨境电商账号涉及多个方面&#xff0c;包括多个账户的安全性、合规性、操作效率等。以下是一些我自己实操的策略和实践&#xff0c;希望能够帮助大家更好地管理跨境电商店铺账号。 一、哪些行为…

sqlite--SQL语句进阶

SQL语句进阶 函数和聚合 函数&#xff1a; SQL 语句支持利用函数来处理数据&#xff0c; 函数一般是在数据上执行的&#xff0c; 它给数据的转换和处理提供了方便常用的文本处理函数&#xff1a; 常用的文本处理函数&#xff1a; // 返回字符串的长度 length();//将字符串…

QWidget成员函数功能和使用详细说明(二)(文字+用例+代码+效果图)

文章目录 1.测试工程配置2.成员函数2.1 void setFixedHeight(int h)2.2 void setFixedSize(const QSize &s)2.3 void setFixedSize(int w, int h)2.4 void setFixedWidth(int w)2.5 void setFocus(Qt::FocusReason reason)2.6 void setFocusPolicy(Qt::FocusPolicy policy)…

【LeetCode算法】第101题:对称二叉树

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;递归判定左子树和右子树是否对称。用一个新函数sym来递归判定左子树和右子树是否对称。该函数细节&#xff1a;判定当前传入的两个根节点是否为空&#xff0c;若均为空…

移动电商服务器单点部署

知识图谱 任务一&#xff1a;Web服务器部署 1.知识结构 2.WEB服务器的介绍 Web服务器一般指网站服务器&#xff0c;是指驻留于因特网上提供某种特定类型计算机的程序&#xff0c;Web服务器可以向浏览器等Web客户端提供文档&#xff0c;也可以放置网站文件&#xff0c;让全世界…

23种软件设计模式——工厂模式

工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一&#xff0c;它提供了一种创建对象的方式&#xff0c;使得创建对象的过程与使用对象的过程分离。 工厂模式提供了一种创建对象的方式&#xff0c;而无需指定要创建的具体类。 通过使…

laravel项目配置Facades Redis自动补全,方法查看

问题原因: 因为Laravel的Redis连接实例是通过RedisManger的工厂类创建的,返回的是一个mixin的类型,因此在IDE中不能自动补全Redis的方法,缺少这个功能,使用起来有些麻烦,尤其是Redis有数十个方法,每个方法也有不少参数。 相关部分的代码如下: /*** @mixin \Illumina…

【Python】解决Python报错:AttributeError: ‘generator‘ object has no attribute ‘xxx‘

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

python weakref的应用举例

问题: 有很多时候, 我们想拥有一个实例, 但是不增加引用计数. 怎么解决呢? 场景: 英雄击打怪物, 如果怪物在受到英雄打击前就死了, 我们可以在英雄的实例里面, 使用一个弱引用来引用怪物, 如果还存在就击打, 不存在就不击打.一般的ui系统都有事件系统, ui上触发一个事件, 然…

TCP协议详解及其相关的10个核心机制(面试重点)

TCP协议的报文格式 TCP协议有连接&#xff0c;可靠性传输&#xff0c;面向字节流&#xff0c;全双工。 他的数据格式如图&#xff1a; 根据他的数据格式&#xff0c;在这里我们只知道 16位源端口号&#xff08;表示客户端这里的端口号&#xff09;&#xff0c;16位目的端口号&…

Maven 中的 classifier 属性用过没?

最近训练营有小伙伴问到松哥一个关于 Maven 依赖的问题&#xff0c;涉及到 classifier 属性&#xff0c;随机问了几个小伙伴&#xff0c;都说工作中没用到过&#xff0c;因此简单整篇文章和小伙伴们分享下。 Maven 大家日常开发应该都有使用&#xff0c;Maven 中有一个比较好玩…

读:《An Overview of Diffusion Models Applications……》导览

读&#xff1a;《An Overview of Diffusion Models: Applications,Guided Generation, Statistical Rates and Optimization》 简单说明 这篇文章也是关于 Diffusion 模型的综述&#xff0c;但是这一篇讲的显然不如 2022出的这篇综述 [2209.00796] Diffusion Models: A Compreh…

微信小程序-网络数据请求(配置request合法域名)

1.小程序中网络数据请求的限制 出于安全方面的考虑&#xff0c;小程序官方对数据接口的请求做出了如下两个限制&#xff1a; &#xff08;1&#xff09;只能请求HTTPS类型的接口 &#xff08;2&#xff09;必须将接口的域名添加到信任列表中 如果要请求某个域名下的接口&am…

优化基础(二):线性组合、仿射组合、锥组合、凸组合、线性集合、仿射集合、锥集合、凸集合的理解

文章目录 前言组合线性组合 (linear combination)仿射组合 (affine combination)锥组合 (conic combination)凸组合 (convex combination) 集合仿射集合凸集合 练习&#xff1a;哪个图形是凸的&#xff0c;哪个是仿射的&#xff1f;参考资料 前言 组合侧重于描述由一些基点生成…

MySQL数据库--从创建数据库到删库跑路

目录 MySQL安装: 1. 数据库基本操作1.1 创建数据库1.2 显示当前数据库1.3 删除数据库1.4 使用数据库/选中数据库 2. SQL中的数据类型2.1 数值类型2.2 字符串类型2.3 时间类型 3. 表的操作3.2 创建表3.1 显示数据库中的表3.3 查看表的详细情况3.4 删除表3.5 注释3. 修改列(了解即…

超大功率光伏并网逆变器学习(三相)

1.超大功率用的IGBT开关频率通常很低,比如6KHz 2.线电压和相电压的关系 相电压 A AB线电压-CA线电压 相电压 B BC线电压-AB线电压 相电压 C CA线电压-BC线电压 3.坐标变换 ABC三相信号通过Clark坐标变换得到αβ两相静止信号,其中α与A相重合,β与α…

用任务监听RTOS各任务的运行状态

使用rtos时内存对于单片机来说总是非常抠搜的。 任务分配多了浪费&#xff0c;少了跑不动。 最近看到这个监听任务还是很好用的。 废话不多说。开始操作 第一步在配置文件中打开这几个宏 #define configUSE_TRACE_FACILITY 1 /*为1时启用可视化跟踪调试*/ #define conf…