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

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

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{@Overridepublic 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);}@Overridevoid onClick() { // 输入操作throw new RuntimeException("暂不支持Text的点击事件");}@Overridevoid 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);}@Overridevoid onClick() {mediator.update(content,"text");}@Overridevoid 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);}@Overridevoid onClick() {mediator.update(null,"view");}@Overridevoid 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 {@Overridepublic void beforeNotify(String content) {System.out.println("通知时间:" + new Date());}@Overridepublic void afterNotify(String content) {System.out.println("通知完成");}}private interface Observer {void update(String content);}private static class Student implements Observer {@Overridepublic void update(String content) {if (content.contains("放假")) System.out.println("学生,耶耶耶!");else System.out.println("学生,哦哦哦");}}private static class Teacher implements Observer {@Overridepublic 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 {@Overrideprotected void duty() {System.out.println("写bug AND 解决bug");}}}

3.2 优缺点

优点:

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

缺点:

  1. 增加了类的个数。

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

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

相关文章

ChatGPT AI专题资料合集【65GB】

介绍 ChatGPT & AI专题资料合集【65GB】 &#x1f381;【七七云享】资源仓库&#xff0c;海量资源&#xff0c;无偿分享√

文件系统小册(FusePosixK8s csi)【1 Fuse】

文件系统小册&#xff08;Fuse&Posix&K8s csi&#xff09;【1 Fuse&#xff1a;用户空间的文件系统】 Fuse(filesystem in userspace),是一个用户空间的文件系统。通过fuse内核模块的支持&#xff0c;开发者只需要根据fuse提供的接口实现具体的文件操作就可以实现一个文…

【测评|白嫖】雨云宁波新区,2C4G200M,公测期间全免费!

雨云香港三区云服务器&#xff0c;高性能的 Xeon Platinum 处理器 企业级 NVME SSD 高性能云服务器。 一键白嫖链接&#xff1a;https://www.rainyun.com 本篇纯测评&#xff0c;无任何广告&#xff0c;请放心食用&#xff01;&#xff01; 本次测评服务器配置如下&#xff1…

用万界星空科技低代码平台能快速搭建一个云MES系统

一、低代码平台与MES:智能制造的新篇章 随着工业4.0和智能制造的兴起&#xff0c;企业对于生产过程的数字化、智能化需求日益迫切。传统的MES系统实施周期长、成本高&#xff0c;成为许多企业数字化转型的瓶颈。而低代码开发平台的出现为这一问题提供了新的解决思路。 二、万界…

linux可观测性ebpf(一) ----------- 环境搭建

参考书籍 开发环境 Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-150-generic x86_64) 1.1 下载内核源码 cd /usr/src/ sudo git clone -b v5.4 https://github.com/torvalds/linux.git1.2 下载书中代码 git clone https://github.com/bpftools/linux-observability-with-bpf1.3 编…

海外媒体通稿:9个极具创意的旅游业媒体推广案例分享-华媒舍

如今&#xff0c;旅游业正迅速发展&#xff0c;媒体推广成为吸引游客的关键。为了更好地展示旅游目的地&#xff0c;许多创意而富有创新的媒体推广策略应运而生。本文将介绍九个极富创意的旅游业媒体推广案例&#xff0c;为广大从业者带来灵感和借鉴。 1. 视频系列&#xff1a;…

4. MySQL 约束

文章目录 【 1. 主键约束 PRIMARY KEY 】1.1 在创建表时设置主键约束设置单字段主键在创建表时设置联合主键 1.2 在修改表时添加主键约束1.3 删除主键约束1.4 主键自增长 AUTO_INCREMENT指定自增字段初始值自增字段不连续 【 2. 外键约束 FOREIGN KEY 】2.1 在创建表时设置外键…

Mybatis数据加密解密

文章目录 Mybatis数据加密解密一、自定义注解二、自定义参数处理拦截器结果集拦截器加密解密 Mybatis数据加密解密 方案一&#xff1a;Mybatis拦截器之数据加密解密【Interceptor】 拦截器介绍 Mybatis Interceptor 在 Mybatis 中被当作 Plugin(插件)&#xff0c;不知道为什么…

ARM32开发——LED点灯

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 点灯的两种方式灌入电流法输出电流法扩展板点灯点灯方式点亮LED1-4完整实现 点灯的两种方式 不同颜色LED&#xff0c;达到相同亮度…

[数据集][目标检测]猫狗检测数据集VOC+YOLO格式8291张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8291 标注数量(xml文件个数)&#xff1a;8291 标注数量(txt文件个数)&#xff1a;8291 标注…

ETLCloud中如何使用Kettle组件

ETLCloud中如何使用Kettle组件在当今数据驱动的时代&#xff0c;数据处理和分析已成为企业决策的关键。为了更高效地处理海量数据&#xff0c;ETL&#xff08;Extract, Transform, Load&#xff09;工具变得至关重要。而在众多ETL工具中&#xff0c;Kettle作为一款开源、灵活且…

攻防实战 | 邮件高级威胁检测与自动化响应

历经三个月的时间&#xff0c;年度重磅直播节目Fortinet 2024年度“Demo季”近日终于迎来了备受瞩目的压轴大戏——Demo Day第三期&#xff0c;主题为《新邮件安全下的高级威胁检测与自动化响应》。继成功举办了前两期《企业网络中的多源威胁情报自动化整合与集成》和《应急响应…

Pycharm使用时的红色波浪线报错——形如‘break‘ outside loop

背景&#xff1a; 我在一个方法中&#xff0c;写了一个if判断&#xff0c;写了一个break&#xff0c;期望终止这个函数&#xff0c;编辑器出现报错 形如下图 视频版问题教程&#xff1a; Pycharm下出现波浪线报错&#xff0c;形如break outside loop 过程&#xff1a; 很奇…

IDEA一键启动多个微服务

我们在做微服务项目开发的时候&#xff0c;每次刚打开IDEA&#xff0c;就需要把各个服务一个个依次启动&#xff0c;特别是服务比较多时&#xff0c;逐个点击不仅麻烦还费时。下面来说一下如何一键启动多个微服务。 操作步骤 点击Edit Configurations 2.点击“”&#xff0c;…

【设计模式】JAVA Design Patterns——Facade(外观模式)

&#x1f50d;目的 为一个子系统中的一系列接口提供一个统一的接口。外观定义了一个更高级别的接口以便子系统更容易使用。 &#x1f50d;解释 真实世界例子 一个金矿是怎么工作的&#xff1f;“嗯&#xff0c;矿工下去然后挖金子&#xff01;”你说。这是你所相信的因为你在使…

性价比为王,物流商怎么选择高效的国际物流管理平台

在全球化贸易日益繁荣的今天&#xff0c;国际物流行业作为链接国内商家和海外市场的重要桥梁&#xff0c;发挥着极其重要的作用。 然而&#xff0c;随着国际物流市场竞争的加剧&#xff0c;对物流商来说&#xff0c;也面临着成本管控和效率提升的双重挑战。今天我们会重点探讨…

解决 DataGrip 2024.1.3 连接 Tdengine 时timestamp字段显示时区不正确问题

设置中找到该设置&#xff0c;将原来的设置 yyyy-MM-dd HH:mm:ss 修改为: yyyy-MM-dd HH:mm:ss.SSS z 即可。 注意&#xff1a;只能修改第一个,修改后提示错误&#xff0c;但是查询数据时能成功格式化时间&#xff0c;修改第二个不生效&#xff0c;可能是 bug 具体格式见: Date…

Opera 浏览器与Google联手,推出由Gemini驱动的全新AI功能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

富士摄像机X-H2S MOV格式化后重新写入后的恢复方法

X-H2S是富士数码的一款旗舰机型&#xff0c;支持4K/6K高清&#xff0c;视频编码为最新的HVC。下面我们来看下富士数码摄像机恢复案例。 故障存储:512G存储卡 Exfat文件系统 故障现象: 512G的卡误格式化后又进行了拍摄&#xff0c;卡使用了120G不到的空间&#xff0c;其它底…

【EFK日志系统】docker一键部署kibana、es-head

docker一键部署kibana、es-head kibana部署es-head部署 上一篇文章搭建了es集群 规划服务器是 es01:172.23.165.185 es02:172.23.165.186 es03:172.23.165.187 那么kibana就搭建在主节点es01:172.23.165.185 按照顺序参考&#xff1a; docker一键部署EFK系统&#xff08;elas…