【再探】設計模式—中介者模式、觀察者模式及模板方法模式

?中介者模式讓多對多的復雜引用關系變成一對多,同時能通過中間類來封裝多個類中的行為,觀察者模式在目標狀態更新時能自動通知給訂閱者,模版方法模式則是控制方法的執行順序,子類在不改變算法的結構基礎上可以擴展功能實現。

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.pswp.cn/bicheng/20169.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20169.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20169.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

003 MySQL

文章目錄 左外連接、右外連接 的區別where/having的區別執行順序聚合 聚合函數MySQL約束事務一致性一致性的含義一致性在事務中的作用如何維護一致性 存儲引擎 Innodb MyIsam區別事務的ACID屬性數據庫的隔離級別MySQL中的并發問題1. 鎖等待和死鎖2. 并發沖突3. 臟讀、不可重復讀…

理解接口回調及其在 RabbitMQ 中的實際運用

介紹 接口回調是一種常見的編程模式&#xff0c;它在異步編程中發揮著重要作用。本文將通過一個簡單的示例介紹接口回調的概念和原理&#xff0c;并探討它在 RabbitMQ 中的實際應用。 接口回調的概念 接口回調是一種編程模式&#xff0c;用于在異步編程中實現回調機制。它允許…

ChatGPT AI專題資料合集【65GB】

介紹 ChatGPT & AI專題資料合集【65GB】 &#x1f381;【七七云享】資源倉庫&#xff0c;海量資源&#xff0c;無償分享√

stm32和esp32硬件資源上有什么區別 哪個更適合初學者

對于初學者來說&#xff0c;ESP32和STM32都有各自的優點和適用場景&#xff0c;但通常ESP32被認為是更適合初學者的選擇&#xff0c;原因如下&#xff1a; 內置無線通信&#xff1a;ESP32集成了WiFi和藍牙功能&#xff0c;這意味著初學者可以更容易地構建無線通信應用&#xff…

文件系統小冊(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;…

【Python面試題收錄】Python的GIL機制

Python中的全局解釋器鎖&#xff08;Global Interpreter Lock&#xff0c;簡稱GIL&#xff09;&#xff0c;同一進程中假如有多個線程運行&#xff0c;一個線程在運行python程序的時候會霸占python解釋器&#xff08;加了一把鎖即GIL&#xff09;&#xff0c;使該進程內的其他線…

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作為一款開源、靈活且…

c#面向對象:接口詳解

接口&#xff08;interface&#xff09; 抽象類中的抽象方法只規定了不能是 private 的&#xff0c;而接口中的“抽象方法”只能是 public 的。這樣的成員訪問級別就決定了接口的本質&#xff1a;接口是服務消費者和服務提供者之間的契約。既然是契約&#xff0c;那就必須是透…

攻防實戰 | 郵件高級威脅檢測與自動化響應

歷經三個月的時間&#xff0c;年度重磅直播節目Fortinet 2024年度“Demo季”近日終于迎來了備受矚目的壓軸大戲——Demo Day第三期&#xff0c;主題為《新郵件安全下的高級威脅檢測與自動化響應》。繼成功舉辦了前兩期《企業網絡中的多源威脅情報自動化整合與集成》和《應急響應…

【持久層】在Spring Boot中使用Hibernate和Gradle構建項目

Hibernate是一個廣泛使用的Java持久化框架&#xff0c;它使得Java對象與關系數據庫之間的映射變得簡單高效。在Spring Boot應用中&#xff0c;結合Gradle構建工具&#xff0c;能夠方便地集成和使用Hibernate。本文將簡述如何在Spring Boot中使用Hibernate&#xff0c;并通過Gra…

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;…