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

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

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. 增加了类的个数。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 之SQLAlchemy使用详细说明

目录 1、SQLAlchemy 1.1、ORM概述 1.2、SQLAlchemy概述 1.3、SQLAlchemy的组成部分 1.4、SQLAlchemy的使用 1.4.1、安装 1.4.2、创建数据库连接 1.4.3、执行原生SQL语句 1.4.4、映射已存在的表 1.4.5、创建表 1.4.5.1、创建表的两种方式 1、使用 Table 类直接创建表…

【稳定检索/投稿优惠】2024年商务、信息管理与大数据经济国际会议(BIMBDE 2024)

2024 International Conference on Business, Information Management, and Big Data Economy 2024年商务、信息管理与大数据经济国际会议 【会议信息】 会议简称&#xff1a;BIMBDE 2024 大会地点&#xff1a;中国北京 会议官网&#xff1a;www.bimbde.com 会议邮箱&#xff…

MySql part1 安装和介绍

MySql part1 安装和介绍 数据 介绍 什么是数据库&#xff0c;数据很好理解&#xff0c;一般来说数据通常是我们所认识的 描述事物的符号记录&#xff0c; 可以是数字、 文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;它们都以经过数字化后存入计算机…

CS4344国产替代音频DAC数模转换芯片DP7344采样率192kHz

目录 DAC应用简介DP7344简介结构框图DP7344主要特性微信号&#xff1a;dnsj5343参考原理图 应用领域 DAC应用简介 DAC&#xff08;中文&#xff1a;数字模拟转换器&#xff09;是一种将数字信号转换为模拟信号&#xff08;以电流、电压或电荷的形式&#xff09;的设备。电脑对…

Golang | Leetcode Golang题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; func maxProfit(prices []int) int {buy1, sell1 : -prices[0], 0buy2, sell2 : -prices[0], 0for i : 1; i < len(prices); i {buy1 max(buy1, -prices[i])sell1 max(sell1, buy1prices[i])buy2 max(buy2, sell1-prices[i])sell2 m…

Docker 环境下 3D Guassian Splatting 的编译和配置

Title: Docker 环境下 3D Guassian Splatting 的编译和配置 文章目录 前言I. 宿主系统上的安装配置1. 安装 nvidia driver2. 安装 docker3. 安装 nvidia-container-toolkit II. Docker 容器安装配置1. 拉取 ubuntu 22.042. 创建容器3. 进入容器4. 容器中安装 cuda SDK5. 容器中…

python class __new__、__init__、__call__ 区别

在Python中&#xff0c;__new__、__init__ 和 __call__ 是三个不同的特殊方法&#xff0c;它们在类的创建和调用过程中扮演着不同的角色。以下是它们的区别和用法&#xff1a; 1. __new__ 方法 作用&#xff1a;__new__ 是一个静态方法&#xff0c;负责创建并返回一个新的实例…

携手亚马逊云科技,神州泰岳如何打通生成式AI落地最后三公里

导读&#xff1a;神州泰岳成为首批获得亚马逊云科技生成式AI能力认证的合作伙伴。 “过去6年来&#xff0c;在与亚马逊云科技的合作过程中&#xff0c;我们大概签约了300家以上的中国出海企业。”近日在一次沟通会上&#xff0c;神州泰岳副总裁兼云事业部总经理刘家歆这样向媒…

idea中使用maven-helper插件阅读排查【经典版】2

一 maven-helper的使用 1.1 helper页面 打开pom文件&#xff0c;并可以切换tab&#xff0c;简单使用&#xff0c;如下图&#xff1a; Conflicts&#xff08;查看冲突&#xff09; All Dependencies as List&#xff08;列表形式查看所有依赖&#xff09; All Dependencies …

【vue3|第4期】Vue3的选项式与组合式

日期&#xff1a;2024年5月30日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

解析前端开发中同源策略与配置代理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 在前端开发中&#xff0c;跨域请求是一个常见的问题。同源策略限制了浏览器中一个页面…

win10系统下WPS工具显示灰色全部用不了,提示登录

如果你在写文档或使用excel时发现导航栏的工具全部使用不了&#xff0c;弹出是需要您登录&#xff0c;可以通过以下操作不用登录。 按照 1&#xff08;搜索框&#xff09;—> 2&#xff08;应用&#xff09;—> 3&#xff08;WPS Office&#xff09;点鼠标左键—> 4&a…

使用LeanCloud平台的即时通讯

LeanCloud 是领先的 Serverless 云服务&#xff0c;为产品开发提供强有力的后端支持&#xff0c;旨在帮助开发者降低研发、运营维护等阶段投入的精力和成本。 LeanCloud 整合了各项服务&#xff0c;让开发者能够聚焦在核心业务上&#xff0c;为客户创造更多价值。 *即时通讯 …

PromptIR论文阅读笔记

MZUAI和IIAI在NIPS2023上的一篇论文&#xff0c;用prompt来编码degradation&#xff0c;然后用来guide restoration network&#xff0c;使得模型能够泛化到不同degradation types and levels&#xff0c;也就是说是一个模型一次训练能够应对多种degradation的unified model。文…

apache大数据各组件部署搭建(超级详细)

apache大数据数仓各组件部署搭建 第一章 环境准备 1. 机器规划 准备3台服务器用于集群部署,系统建议CentOS7+,2核8G内存 172.19.195.228 hadoop101 172.19.195.229 hadoop102 172.19.195.230 hadoop103 [root@hadoop101 ~]# cat /etc/redhat-release CentOS Linux rele…

Azure DevOps Server 2022.2(升级过程)

1. 概述 2. 前期准备3. 升级过程4. 验证成果 1. 概述 本月微软公司发布了Azure DevOps Server 2022的第二个升级包Update 2 https://learn.microsoft.com/en-us/azure/devops/server/release-notes/azuredevops2022u2。 自2024年3月12日发布Azure DevOps Server 2022 Update 1(…

Linux综合实践(Ubuntu)

目录 一、配置任务 1.1 配置该服务器的软件源为中科大软件源 1.2 安装相关软件openssh-server和vim 1.3 设置双网卡&#xff0c;网卡1为NAT模式&#xff0c;网卡2为桥接模式(桥接模式下&#xff0c;使用静态ip&#xff0c;该网卡数据跟实验室主机网络设置相似&#xff0c;除…

Jvm(一)之栈、堆、方法区

前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入工作的漩涡&#xff0c;忘记了停下脚步&#xff0c;感受周围的世界。让我们一起提醒自己&#xff0c;要适时放慢脚步…

中文多模态InternVL-Chat-V1-5,中文理解能力强劲,8 项指标超越商业模型,性能媲美 GPT-4V

前言 近年来&#xff0c;多模态大型语言模型&#xff08;MLLM&#xff09;的快速发展&#xff0c;为人工智能在图像、文本等多模态信息理解和处理方面带来了前所未有的突破。然而&#xff0c;现有的主流多模态模型多以英文为训练语言&#xff0c;在中文理解和处理方面存在着明…

SwiftUI中Popover的使用(弹出方式,箭头位置,如何退出)

在iOS中&#xff0c;popover是出现在现有内容顶部的UI元素&#xff0c;通常用于在上下文中向用户呈现新视图。与其他占用整个屏幕的视图控制器不同&#xff0c;popover出现在一个较小的、集中的区域&#xff0c;从而使用户能够在必要时与popover外的应用程序的其他部分进行交互…