目錄
程式碼背景
觀察者模式
介紹
實作
觀察者(學生)
通知者(老師)
Main方法
 委託介紹
觀察者
通知者
 事件
事件處理
 總結
首頁 Java java教程 Java中觀察者模式與委託的實例比較分析

Java中觀察者模式與委託的實例比較分析

May 08, 2023 pm 04:37 PM
java

    程式碼背景

    一個班級,有兩類學生,A類別:不學習,玩,但是玩的東西不一樣,有的是做遊戲,有的是看電視

    B類:放哨的學生,專門看老師的動向,如果老師進班了就立刻通知大家。

    如此就形成了一個需求,放哨的學生要通知所有玩的學生:老師來了,而不同的學生有不同的反應,有的馬上把電視關閉,有的停止玩遊戲。

    觀察者模式

    介紹

    觀察者模式:定義了一個一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題對象。
    這個主題對像在狀態改變時,會通知所有的觀察者對象,使他們能夠自動更新自己。

    主要解決:一個物件狀態改變給其他物件通知的問題,而且要考慮到易用和低耦合,保證高度的協作。

    何時使用:一個物件(目標物件)的狀態改變,所有的依賴物件(觀察者物件)都會被通知,進行廣播通知。

    如何解決:使用物件導向技術,可以將這種依賴關係弱化。

    關鍵程式碼:在抽象類別裡有一個 ArrayList 存放觀察者。

    實作

    Java中觀察者模式與委託的實例比較分析

    觀察者(學生)
    /**
     * 抽象的观察者
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/10 - 15:32
     */
    public interface Observer {
        public abstract void updateState();
    }
    /**
     * 具体的观察者
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/10 - 15:39
     */
    public class ConcreteObserver implements Observer{
        //观察者的姓名
        private String name;
        //观察者的状态
        private String observerState;
        //明确具体的通知者
        private ConcreteSubject subject;
       //get set方法省略
        public ConcreteObserver(String name, ConcreteSubject subject) {
            this.name = name;
            this.subject = subject;
        }
        @Override
        public void updateState() {
            observerState=subject.getSubjectState();
            System.out.println(name+"在打游戏");
            String str=String.format("观察者%s的:新状态是%s", name,observerState);
            System.out.println(str);
        }
    }
    /**
     * 具体的观察者
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/10 - 15:39
     */
    public class ConcreteObserver2 implements Observer{
        //观察者的姓名
        private String name;
        //观察者的状态
        private String observerState;
        //明确具体的通知者
        private ConcreteSubject subject;
       //get set方法省略
        public ConcreteObserver2(String name, ConcreteSubject subject) {
            this.name = name;
            this.subject = subject;
        }
        @Override
        public void updateState() {
            observerState=subject.getSubjectState();
            System.out.println(name+"在看电视");
            String str=String.format("观察者%s:新状态是%s", name,observerState);
            System.out.println(str);
        }
    }
    登入後複製
    通知者(老師)
    /**
     * 抽象的通知者
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/10 - 15:30
     */
    public abstract class Subject {
        //管理观察者的集合
        private List<Observer> observers=new ArrayList<>();
        //增加观察者
        public void add(Observer observer){
            observers.add(observer);
        }
        //减少观察者
        public void detach(Observer observer){
            observers.remove(observer);
        }
        /**
         * 通知所有的观察者
         */
        public void notifyMsg(){
            for (Observer observer : observers) {
                observer.updateState();
            }
        }
    }
    /**
     * 具体的通知者
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/10 - 15:38
     */
    public class ConcreteSubject extends Subject {
        //通知者的状态
        private String subjectState;
        //get set方法
        public String getSubjectState() {
            return subjectState;
        }
        public void setSubjectState(String subjectState) {
            this.subjectState = subjectState;
        }
    }
    登入後複製
    Main方法
    /**
     * 控制台Main方法
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/10 - 15:48
     */
    public class MainTest {
        public static void main(String[] args) {
            //创建一个主题/通知者
            ConcreteSubject subject=new ConcreteSubject();
            //new出观察者(学生)
            ConcreteObserver studentZhang = new ConcreteObserver("小张", subject);
            ConcreteObserver studentLiu = new ConcreteObserver("小刘", subject);
            ConcreteObserver studentWang = new ConcreteObserver("小王", subject);
            //将观察者添加到通知队列里
            subject.add(studentZhang);
            subject.add(studentLiu);
            subject.add(studentWang);
            //通知者(老师)状态修改,通知每个学生
            subject.setSubjectState("老师回来了,我要好好学习");
            subject.notifyMsg();
            System.out.println("-----------");
        }
    }
    登入後複製

    Java中觀察者模式與委託的實例比較分析

     委託介紹

    #委託可以看做是函數的抽象,是函數的「類別」。委託的實例將代表一個具體的函數
    一個委託可以搭載多個方法,所有的方法都被依次喚起。可以使委託對象所搭載的方法並不需要屬於同一類。
    委託事件模型可以由三個元件定義:事件、事件來源和事件偵聽器。

    委託的實作簡單來講就是用反射來實現的。

    實作

    Java中觀察者模式與委託的實例比較分析

    觀察者
    /**
     * 监听器/观察者 玩游戏
     * 事件监听器
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:17
     */
    public class PlayingGameListener {
        public PlayingGameListener(){
            System.out.println("我正在玩游戏 开始时间"+new Date());
        }
        public void stopPlayingGame(Date date){
            System.out.println("老师来了,快回到座位上,结束时间"+date);
        }
    }
    /**
     * 监听器/观察者 看电视
     * 事件监听器
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:17
     */
    public class WatchingTVListener {
        public WatchingTVListener(){
            System.out.println("我正在看电视 "+new Date());
        }
        public void stopWatchingTV(Date date){
            System.out.println("老师来了,快关闭电视 。 结束时间"+date);
        }
    }
    登入後複製
    通知者
    /**
     * 通知者的抽象类
     * 事件源
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:15
     */
    public abstract class Notifier {
        //每个通知者都有一个需要通知的队列(通知:对象、方法、参数)
        private EventHandler eventHandler=new EventHandler();
        public EventHandler getEventHandler() {
            return eventHandler;
        }
        public void setEventHandler(EventHandler eventHandler) {
            this.eventHandler = eventHandler;
        }
        //增加需要帮忙放哨的学生
        public abstract void addListener(Object object,String methodName,Object...args);
        //告诉所有要帮忙放哨的学生:老师来了
        public abstract void notifyX();
    }
    /**
     * 通知者的子类,放哨人
     * 事件源
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:15
     */
    public class GoodNotifier extends Notifier {
        @Override
        public void addListener(Object object, String methodName, Object...args) {
            System.out.println("有新的同学委托尽职尽责的放哨人!");
            this.getEventHandler().addEvent(object, methodName, args);
        }
        @Override
        public void notifyX() {
            System.out.println("尽职尽责的放哨人告诉所有需要帮忙的同学:老师来了");
            try{
                //优化:异步通知
                this.getEventHandler().notifyX();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    登入後複製
     事件
    /**
     * 抽象出的事件类,也可以称为方法类
     * 事件
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:03
     */
    public class Event {
        //要执行方法的对象
        private Object object;
        //要执行的方法名称
        private String methodName;
        //要执行方法的参数
        private Object[] params;
        //要执行方法的参数类型
        private Class[] paramTypes;
        //若干setter getter
        public Object getObject() {
            return object;
        }
        public String getMethodName() {
            return methodName;
        }
        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }
        public Object[] getParams() {
            return params;
        }
        public void setParams(Object[] params) {
            this.params = params;
        }
        public Class[] getParamTypes() {
            return paramTypes;
        }
        public void setParamTypes(Class[] paramTypes) {
            this.paramTypes = paramTypes;
        }
        public Event(){
        }
        public Event(Object object,String methodName,Object...args){
            this.object=object;
            this.methodName=methodName;
            this.params=args;
            contractParamTypes(this.params);
        }
        //根据参数数组生成参数类型数组
        private void contractParamTypes(Object[] params){
            this.paramTypes=new Class[params.length];
            for(int i=0;i<params.length;i++){
                this.paramTypes[i]=params[i].getClass();
            }
        }
        //执行该 对象的该方法
        public void invoke() throws Exception{
            //通过class,method,paramTypes 确定执行哪个类的哪个方法
            Method method=object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
            if(null==method){
                return;
            }
            //方法执行
            method.invoke(this.getObject(), this.getParams());
        }
    }
    登入後複製
    事件處理
    /**
     * 管理哪些事件需要执行
     * 管理事件
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:03
     */
    public class EventHandler {
        //是用一个List
        private List<Event> objects;
        //添加某个对象要执行的事件,及需要的参数
        public void addEvent(Object object,String methodName,Object...args){
            objects.add(new Event(object,methodName,args));
        }
        public EventHandler(){
            objects=new ArrayList<Event>();
        }
        //通知所有的对象执行指定的事件
        public void notifyX() throws Exception{
            for(Event e : objects){
                e.invoke();
            }
        }
    }
    登入後複製

    Main方法

    /**
     * 启动类
     *
     * @author Promsing(张有博)
     * @version 1.0.0
     * @since 2022/5/8 - 11:19
     */
    public class EventMain {
        public static void main(String[] args) {
            //创建一个尽职尽责的放哨者
            Notifier goodNotifier = new GoodNotifier();
            //创建一个玩游戏的同学,开始玩游戏
            PlayingGameListener playingGameListener = new PlayingGameListener();
            //创建一个看电视的同学,开始看电视
            WatchingTVListener watchingTVListener = new WatchingTVListener();
            //玩游戏的同学告诉放哨的同学,老师来了告诉一下
            goodNotifier.addListener(playingGameListener, "stopPlayingGame", new Date());
            //看电视的同学告诉放哨的同学,老师来了告诉一下
            goodNotifier.addListener(watchingTVListener, "stopWatchingTV", new Date());
            try {
                //一点时间后
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //老师出现,放哨的人通知所有要帮忙的同学:老师来了
            goodNotifier.notifyX();
        }
    }
    登入後複製

    Java中觀察者模式與委託的實例比較分析

     總結

    1.先有觀察者模式後有委託事件技術
    2.觀察者模式只能通知繼承Observer類別的子類,也可以將Observer改成介面

    for (Observer observer : observers) {
            observer.updateState();
    }
    登入後複製

    3.委託可以通知任何類別的任何方法。反射、everone

     Method method=object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
    if(null==method){
            return;
    }
     method.invoke(this.getObject(), this.getParams());
    登入後複製

    4.委託與觀察者比多了一個事件執行者,解除觀察者與通知者的耦合,可以做到通知任何物件的任何方法。讓A類學生和B類學生完全解耦,也就是A類完全不知道B類的學生,卻可以通知B類的學生

    6.建立一套觸發機制,可以使用非同步通知

    7.觀察者/委託挺像MQ裡邊的訂閱發布。生產者、隊列、消費者。

    以上是Java中觀察者模式與委託的實例比較分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.如果您聽不到任何人,如何修復音頻
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25:如何解鎖Myrise中的所有內容
    4 週前 By 尊渡假赌尊渡假赌尊渡假赌

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

    Java 完美數指南。這裡我們討論定義,如何在 Java 中檢查完美數?

    Java 中的隨機數產生器 Java 中的隨機數產生器 Aug 30, 2024 pm 04:27 PM

    Java 隨機數產生器指南。在這裡,我們透過範例討論 Java 中的函數,並透過範例討論兩個不同的生成器。

    Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

    Java 版 Weka 指南。這裡我們透過範例討論簡介、如何使用 weka java、平台類型和優點。

    Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

    Java 史密斯數指南。這裡我們討論定義,如何在Java中檢查史密斯號?帶有程式碼實現的範例。

    Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

    在本文中,我們保留了最常被問到的 Java Spring 面試問題及其詳細答案。這樣你就可以順利通過面試。

    突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

    Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

    Java 中的時間戳至今 Java 中的時間戳至今 Aug 30, 2024 pm 04:28 PM

    Java 中的時間戳記到日期指南。這裡我們也結合範例討論了介紹以及如何在java中將時間戳記轉換為日期。

    創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

    Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

    See all articles