zoukankan      html  css  js  c++  java
  • 观察者模式、发布订阅和事件驱动

      观察者模式(有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

      观察者模式(Observer)完美的将观察者和被观察的对象分离开,以明星和粉丝举例子,明星就是被观察着,粉丝就是观察者。下面是一个demo

    package Observer;
    
    public interface Observer {
    
        void update(Observable o);
    }
    package Observer;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Observable {
    
        private List<Observer> list = new ArrayList<>();
        public void addObserver(Observer o) {
            list.add(o);
        }
        private String status;
        
        public List<Observer> getList() {
            return list;
        }
    
        public String getStatus() {
            return status;
        }
    
        public void movelUp (String status) {
            System.out.println(status);
            this.status = status;
            list.stream().forEach(o -> o.update(this));
        }
        
    }
    package Observer;
    
    public class Client {
    
        public static void main(String[] args) {
            Observable ob = new Observable();
            ob.addObserver(new ObserverImpl("小花"));
            ob.addObserver(new ObserverImpl("小名"));
            ob.movelUp("天下无贼");
        }
    }

      以上便是标准的观察者模式,在被观察着中维护了一个观察者的列表,需要由被观察者去完成注册观察者的功能,不符合单一职责原则。所以我们需要添加一个manager类,来方便用户自己去订阅某个明星。改造代码如下:

    package Observer2;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Star {
    
        private String name;
    
        private String lastMovel;
    
        // 标识被观察者是否变化
        private boolean changed = false;
    
        private List<Observer> list = new ArrayList<>();
    
        public void addObserver(Observer o) {
            list.add(o);
        }
    
        public List<Observer> getList() {
            return list;
        }
    
        public void notifyObserver() {
            if (!changed) {
                return;
            }
            setChanged(false);
            list.stream().forEach(o -> o.update(this, null));
        }
    
        public boolean isChanged() {
            return changed;
        }
    
        public void setChanged(boolean changed) {
            this.changed = changed;
        }
    
        public void setList(List<Observer> list) {
            this.list = list;
        }
    
        public Star(String name) {
            super();
            this.name = name;
            Manager.getInstance().addStar(this);
        }
    
        
        public void movelUp(String movel) {
            System.out.println(name + "发布了" + movel);
            this.lastMovel = movel;
            setChanged(true);
            notifyObserver();
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getLastMovel() {
            return lastMovel;
        }
    
        public void setLastMovel(String lastMovel) {
            this.lastMovel = lastMovel;
        }
    
    }
    package Observer2;
    
    public interface Observer {
    
        void update(Star o,Object args);
    }
    package Observer2;
    
    public class Fans implements Observer {
        
        private String name;
        
        
    
        public Fans(String name) {
            super();
            this.name = name;
        }
    
    
    
        public String getName() {
            return name;
        }
    
    
    
        public void setName(String name) {
            this.name = name;
        }
    
    
        public void subscribe(String starName) {
            Manager.getInstance().getStar(starName).addObserver(this);
        }
    
        @Override
        public void update(Star star,Object args) {
            System.out.println(name + "得到了" + star.getName() +"发布" + star.getLastMovel() + "的消息");
        }
    
        
    }
    package Observer2;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Manager {
    
        private Map<String, Star> observableMap = new HashMap<>();
        
        private Manager() {
            
        }
        public void addStar(Star star) {
            observableMap.put(star.getName(), star);
        }
        public Star getStar(String name) {
            return observableMap.get(name);
        }
        public static Manager getInstance() {
            return SingleManager.manager;
        }
        private static class SingleManager{
            private static Manager manager = new Manager();
            
        }
        
        
    }
    package Observer2;
    
    public class Client {
    
        public static void main(String[] args) {
            Fans fans1 = new Fans("小明");
            Fans fans2 = new Fans("小话");
            Fans fans3 = new Fans("小张");
            Fans fans4 = new Fans("小里");
            Star star1 = new Star("丽影");
            Star star2 = new Star("幂幂");
            fans1.subscribe("丽影");
            fans3.subscribe("幂幂");
            fans4.subscribe("幂幂");
            star1.movelUp("乘风破浪");
            star2.movelUp("孤岛惊魂");
            System.out.println("----------------------------");
            fans2.subscribe("丽影");
            star1.movelUp("女儿国");
        }
    }

      发布/订阅模式(Pub/Sub)是一种消息模式,它有 两个参与者 :  发布者和订阅者 。发布者向 某个信道发布一条消息,订阅者绑定这个信道,当有消息发布至信道时就会 接收到一个通知。最重要的一点是, 发布者和订阅者是完全解耦的,彼此并不知晓对方的存在。从定义上可以看出,发布订阅模式里双方是完全解耦的,而在观察者模式里,目标对象管理这观察者,双方是耦合的,这是最主要的区别,而在发布订阅模式中多了一个中间层信道。我们常用的activeMQ、rabbitMQ、kafka等中间件就是为发布订阅模式服务的。

      还有一种和观察者模式很像的就是事件驱动模型,相信各位都知道tomcat,在使用的过程中,或许经常会有人用到listener,即监听器这个概念。那么其实这个就是一个事件驱动模型的应用。比如我们的spring,我们在应用启动的时候要初始化我们的IOC容器,那么我们的做法就是加入一个listener,这样伴随着tomcat服务器的启动,spring的IOC容器就会跟着启动。那么这个listener其实就是事件驱动模型中的监听器,它用来监听它所感兴趣的事,比如我们springIOC容器启动的监听器,就是实现的ServletContextListener这个接口,说明它对servletContext感兴趣,会监听servletContext的启动和销毁。事件驱动模型与观察者模式勉强的对应关系可以看成是,被观察者相当于事件源,观察者相当于监听器,事件源会产生事件,监听器监听事件。所以这其中就搀和到四个类,事件源,事件,监听器以及具体的监听器。下面我们就将上面的例子改造为事件驱动模型。

    package Observer3;
    
    import java.util.EventObject;
    
    public class MovelEvent extends EventObject {
    
        private static final long serialVersionUID = -1231609728871248531L;
    
        public MovelEvent(Star star) {
            super(star);
        }
    
        public Star getStar() {
            return (Star) super.getSource();
        }
    }
    package Observer3;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Star {
        // 标识被观察者是否变化
        private boolean changed = false;
    
        private List<MovelListener> list = new ArrayList<>();
    
        public void addMovelListener(MovelListener o) {
            list.add(o);
        }
    
        public List<MovelListener> getList() {
            return list;
        }
    
        public void setList(List<MovelListener> list) {
            this.list = list;
        }
    
        public void notifyObserver() {
            if (!changed) {
                return;
            }
            setChanged(false);
            MovelEvent movelEvent = new MovelEvent(this);
            list.stream().forEach(o -> o.update(movelEvent));
        }
    
        public boolean isChanged() {
            return changed;
        }
    
        public void setChanged(boolean changed) {
            this.changed = changed;
        }
    
    
        public Star(String name) {
            super();
            this.name = name;
            Manager.getInstance().addStar(this);
        }
    
        private String name;
    
        private String lastMovel;
    
        public void movelUp(String movel) {
            System.out.println(name + "发布了" + movel);
            this.lastMovel = movel;
            setChanged(true);
            notifyObserver();
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getLastMovel() {
            return lastMovel;
        }
    
        public void setLastMovel(String lastMovel) {
            this.lastMovel = lastMovel;
        }
    
    }
    package Observer3;
    
    import java.util.EventListener;
    
    public interface MovelListener extends EventListener {
        
        void update (MovelEvent movelEvent);
    
    }
    package Observer3;
    
    public class Fans implements MovelListener {
        
        private String name;
        
        
    
        public Fans(String name) {
            super();
            this.name = name;
        }
    
    
    
        public String getName() {
            return name;
        }
    
    
    
        public void setName(String name) {
            this.name = name;
        }
    
    
        public void subscribe(String starName) {
            Manager.getInstance().getStar(starName).addMovelListener(this);
        }
    
        @Override
        public void update(MovelEvent movelEvent) {
            Star star = movelEvent.getStar();
            System.out.println(name + "得到了" + star.getName() +"发布" + star.getLastMovel() + "的消息");
            
        }
    
        
    }

       我们彻底将刚才的观察者模式改成了事件驱动,现在我们使用事件驱动的类再运行一下客户端,其中客户端代码和WriterManager类的代码是完全不需要改动的,直接运行客户端即可。我们会发现得到的结果与观察者模式一模一样。

      那么观察者模式和事件驱动的不同之处在哪里呢?首先从实现方式上就能看出,事件驱动可以解决观察者模式的问题,但反过来则不一定,另外二者所表达的业务场景也不一样,比如上述例子,使用观察者模式更贴近业务场景的描述,而使用事件驱动,从业务上讲,则有点勉强。再者从功能上讲,观察者模式中观察者的响应理论上讲针对特定的被观察者是唯一的(当然如果在update方法中ifelse则也能实现对多个被观察着);事件驱动则更灵活,可以定义自己感兴趣的事情,比如我们可以监听movel,也可以在接口里加一个singListener的接口,然后我们的fans同时实现这个接口,那么star在发布singEvent的时候,只要实现了singListener的类的实例就可以收到消息,当然程序的复杂性就增加了。

      最后总结一下,观察者模式和发布订阅模型的区别就在于消息是否发送给中间件,观察者和被观察着是否完全解耦;而观察者模式和事件驱动的区别则在于事件驱动则更加灵活,但同时增加了程序的复杂性。

      

  • 相关阅读:
    涡轮增压中冷器
    TortoiseSVN文件及文件夹图标不显示解决方法
    无线路由器无法登录管理界面,怎么办?
    TP-LINK-TL-WVR450G路由器经常断网
    阿里云DNS地址
    农村社保和职工社保能同时交吗?
    电视机顶盒遥控器可以同时遥控电视和机顶盒
    各种汽车的高端品牌
    金蝶云星空系统打印提示:对象不支持“SetGraphicsMode”属性或方法
    怎么去掉视频的背景音乐?
  • 原文地址:https://www.cnblogs.com/hhhshct/p/10297872.html
Copyright © 2011-2022 走看看