首頁 > Java > java教程 > 主體

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

WBOY
發布: 2023-05-08 16:37:08
轉載
779 人瀏覽過

    程式碼背景

    一個班級,有兩類學生,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中文網其他相關文章!

    相關標籤:
    來源:yisu.com
    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
    熱門教學
    更多>
    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板