• Observer 观察者模式 MD


    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
    MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

    Observer 观察者模式 设计模式


    目录

    简介

    观察者模式有时又被称为发布-订阅(publish-Subscribe)模式、模型-视图(model-View)模式、源-收听者(Source-listener)模式,或从属者模式。在此种模式中,一个【目标物件】管理所有相依于它的观察者物件,并且在它本身的状态改变时【主动】发出通知。这通常通过调用各观察者所提供的接口来实现。此种模式通常被用来实现事件处理系统。

    观察者模式定义了对象间的【一对多】关系,当一个对象的行为、状态发生变化时,所有订阅者能够收到相应的通知。

    观察者模式一般有2种,一种【推模式】,一个【拉模式】。推模式即当被订阅者对象发生改变时,会主动将变化的消息【推给】订阅者,而不考虑每个订阅者当时的处理能力;另一种是拉模式,即订阅者持有被观察者的实例,当被订阅者的行为发生改变时,拉模式会主动的根据引用【获取】变化的相关数据。

    观察者模式中涉及的角色

    • 抽象主题[Subject]:即被观察者ObServable
    • 具体主题[ConcreteSubject]:在具体主题内部状态改变时,通知观察者
    • 抽象观察者[Observer]:为所有具体观察者定义接口
    • 具体观察者[ConcreteObserver]:可以保存指向具体主题对象的引用

    使用场景 :当一个系统中【某个】对象的改变需要同时改变其他【多个】对象,且它不知道具体有多少对象有待改变时候 使用。
    作用:通知对象状态改变 。

    最简单的观察者模式

    抽象观察者

    interface Watcher {  
        void update(String str);  
    }  

    抽象主题

    interface Watched {  
        void addWatcher(Watcher watcher);  
        void removeWatcher(Watcher watcher);  
        void notifyWatchers(String str);  
    }  

    具体观察者

    class ConcreteWatcher implements Watcher {  
        @Override  
        public void update(String str) {  
            Log.i("bqt", "观察者收到被观察者的消息:" + str);  
        }  
    }  

    具体主题

    class ConcreteWatched implements Watched {  
        private List<Watcher> list = new ArrayList<>();  
    
        @Override  
        public void addWatcher(Watcher watcher) {  
            if (list.contains(watcher)) {  
                Log.i("bqt", "失败,被观察者已经注册过此观察者");  
            } else {  
                Log.i("bqt", "成功,被观察者成功注册了此观察者");  
                list.add(watcher);  
            }  
        }  
    
        @Override  
        public void removeWatcher(Watcher watcher) {  
            if (list.contains(watcher)) {  
                boolean success = list.remove(watcher);  
                Log.i("bqt", "此观察者解除注册观察者结果:" + (success ? "成功" : "失败"));  
            } else {  
                Log.i("bqt", "失败,此观察者并未注册到被观察者");  
            }  
        }  
    
        @Override  
        public void notifyWatchers(String str) {  
            for (Watcher watcher : list) {  
                watcher.update(str);  
            }  
        }  
    }  

    演示案例

    private Watcher watcher;  
    private Watched watched;  
    //...  
    watcher = new ConcreteWatcher();  
    watched = new ConcreteWatched();  
    //...  
    watched.addWatcher(watcher);  
    watched.notifyWatchers("救命啊");  
    watched.removeWatcher(watcher);  

    观察者模式详细案例

    产品对象

    发布者要发布什么给订阅者?订阅者要订阅什么?这中间需要定义一个产品对象:

    class Product {
        public boolean changed = false;
        public String message = "";
        public int num = -1;
    }

    抽象主题 Subject

    也叫抽象被观察者Observable。抽象主题把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者。抽象主题可以增加和删除观察者对象

    interface Subject {
        public void attach(Observer observer); //注册观察者对象
        public void detach(Observer observer); //移除/取消注册观察者对象
        /**---------上面两个是最基本的方法,下面的方法都不是必须的--------*/
        public void nodifyObservers(); //通知所有注册的观察者对象
        public void setProduct(Product product); //把通知的内容封装到一个对象中
        public Product getProduct(); //获取产品对象
    }

    具体主题 ConcreteSubject

    class ConcreteSubject implements Subject {
        private List<Observer> list = new ArrayList<Observer>(); //用来保存注册的观察者对象
        private Product product;
    
        @Override
        public void attach(Observer observer) {
            list.add(observer);
        }
    
        @Override
        public void detach(Observer observer) {
            list.remove(observer);
        }
    
        @Override
        public void nodifyObservers() {
            if (product != null && product.changed) {
                System.out.println("具体主题状态发生改变,于是通知观察者:" + product.message + "-" + product.num);
                for (Observer observer : list) {
                    observer.update(product);
                }
            }
        }
    
        @Override
        public void setProduct(Product product) {
            this.product = product;
        }
    
        @Override
        public Product getProduct() {
            return product;
        }
    }

    抽象观察者 Observer

    为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

    interface Observer {
        public void update(Product product);
    }

    具体观察者 ConcreteObserver

    实现抽象观察者所要求的更新接口。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用

    class ConcreteObserver implements Observer {
        public String name;
        public ConcreteObserver(String name) {
            this.name = name;
        }
    
        @Override
        public void update(Product product) {
            if (product == null) return;
            System.out.println("具体观察者【" + name + "】收到消息:" + product.message + "-" + product.num);
        }
    }

    演示

    public class Test {
        public static void main(String[] args) throws InterruptedException { 
    
            Subject subject = new ConcreteSubject();//主题对象
            Observer observer1 = new ConcreteObserver("包青天");//观察者对象
            Observer observer2 = new ConcreteObserver("白乾涛");
    
            subject.attach(observer1);//将观察者对象注册到主题对象上
            subject.attach(observer2);
    
            Product product = new Product(); //主题发布的产品
            subject.setProduct(product);
    
            //当主题发布的产品对象的状态改变时,主题通知观察者
            product.changed = true;
            product.message = "下载进度";
            product.num = 15;
            subject.nodifyObservers();
    
            //当观察者对象不再需要监控此主题对象时,将观察者对象取消注册到主题对象上
            subject.detach(observer1);
        }
    }

    利用系统提供的两个类

    Observer 源码

    package java.util;
    
    public interface Observer {
        void update(Observable o, Object arg);
    }

    Observable 源码

    package java.util;
    
    public class Observable {
        private boolean changed = false;//标志被观察者是否改变
        private Vector obs;//保存注册的观察者对象
    
        public Observable() {
            obs = new Vector();
        }
    
        public synchronized void addObserver(Observer o) {
            if (o == null) throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        public void notifyObservers(Object arg) {
            Object[] arrLocal;
    
            synchronized (this) {
                if (!changed) return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
        public synchronized void deleteObservers() {
            obs.removeAllElements();
        }
    
        protected synchronized void setChanged() {
            changed = true;
        }
    
        protected synchronized void clearChanged() {
            changed = false;
        }
    
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        public synchronized int countObservers() {
            return obs.size();
        }
    }

    利用系统类演示观察者模式

    被观察者

    继承自Observable

    class HanFeiZi extends Observable {
        public void haveBreakfast() {
            System.out.println("韩非子大吼一声:开饭!");
            setChanged();
            notifyObservers("韩非子开始吃饭了");
        }
    
        public void haveFun() {
            System.out.println("韩非子大吼一声:侍寝!");
            setChanged();
            notifyObservers("韩非子开始娱乐了");
        }
    }

    观察者

    观察者一

    class LiSi implements Observer {
        @Override
        public void update(Observable observable, Object obj) {
             //李斯是个观察者,一旦韩非子有活动,他就收到了谍报
             System.out.println("【李斯】报告秦老板!臣收到谍报,韩非子有新动向--->" + obj.toString()); 
        }
    }

    观察者二

    class MrsHan implements Observer {
        public void update(Observable observable, Object obj) {
            System.out.println("【韩夫人】因为--->" + obj.toString() + "——所以我悲伤呀");
        }
    }

    演示

    public class Test {
        public static void main(String[] args) {
            //定义被观察者
            HanFeiZi hanFeiZi = new HanFeiZi();
    
            //定义观察者
            Observer liSi = new LiSi();
            Observer mrsHan = new MrsHan();
    
            //观察者注册被观察者 
            hanFeiZi.addObserver(liSi);
            hanFeiZi.addObserver(mrsHan);
    
            //然后观察者就可以监视被观察者韩非子的动向
            hanFeiZi.haveBreakfast();
            hanFeiZi.haveFun();
        }
    }

    2018-2-21

  • 相关阅读:
    Linux OS共享文件
    源代码安装软件-MySQL
    细说Linux权限
    Linux进程作业的查看和杀死
    Linux_破解密码-营救模式
    找不同diff-打补丁patch
    WINDOWS自带md5校验工具
    猪,兔,等动物解剖平面图
    利用mimikatz破解远程终端凭据,获取服务器密码
    PHP中通过bypass disable functions执行系统命令的几种方式
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/6016380.html
Copyright © 2020-2023  润新知