美文网首页
观察者模式

观察者模式

作者: c_gentle | 来源:发表于2022-02-16 09:18 被阅读0次
    什么是观察者模式

    观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。
      对于观察者模式而言,肯定有观察者和被观察者之分。比如在一个目录下建立一个文件,这时系统会通知目录管理器增加目录,并通知磁盘减少空间,在这里,文件就是观察者,目录管理器和磁盘就是被观察者。
      观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:

    13931e0b5e88e1dfb6961f3dc62e1d9.png

    其中,Subject类是主题,它把所有对观察者对象的引用文件存在了一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供了一个接口,可以增加和删除观察者对象;Observer类是抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;ConcreteSubject类是具体主题,将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知;ConcreteObserver是具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协同。

    主题Subject

    首先定义一个观察者数组,并实现增、删及通知操作。它的职责很简单,就是定义谁能观察,谁不能观察,用CopyOnWriteArrayList是线程同步的,比较安全,也可以使用ArrayList,是线程异步的,但不安全。

    public class Subject {
        //观察者数组
        private CopyOnWriteArrayList<Observer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
    
        //增加一个观察者
        public void addObserver(Observer observer) {
            this.copyOnWriteArrayList.add(observer);
        }
    
        //删除一个观察者
        public void deleteObserver(Observer observer) {
            this.copyOnWriteArrayList.remove(observer);
        }
    
        //通知所有观察者
        public void notifyObserver() {
            copyOnWriteArrayList.forEach(item -> {
                item.update();
            });
        }
    }
    
    抽象观察者

    观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。

    public interface Observer {
        //更新
        void update();
    }
    
    具体主题

    继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种

    public class ConcreteSubject extends Subject {
        //具体业务
        public void doSomething(){
            //...
            super.notifyObserver();
        }
    }
    
    具体观察者
    public class ConcreteObserver implements Observer{
        @Override
        public void update() {
            System.out.println("收到消息,进行处理");
        }
    }
    
    //客户端
    public class Client {
        public static void main(String[] args) {
            //创建一个主题
            ConcreteSubject subject = new ConcreteSubject();
            //定义一个观察者
            Observer observer=new ConcreteObserver();
            //观察
            subject.addObserver(observer);
            subject.doSomething();
        }
    }
    
    观察者模式的实现

    下面举一个具体实例,假设上班时间有一部分同事在看股票,一部分同事在看NBA,这时老板回来了,前台通知了部分同事老板回来了,这些同事及时关闭了网页没被发现,而没被通知到的同事被抓了个现行,被老板亲自“通知”关闭网页,UML图如下:


    image.png
    通知者接口
    public interface SubjectDemo {
        //增加
        void attach(ObserverDemo observerDemo);
    
        //删除
        void detach(ObserverDemo observerDemo);
    
        //通知
        void notifyObservers();
    
        //状态
        void setAction(String action);
    
        String getAction();
    }
    
    观察者接口
    public abstract class ObserverDemo {
        protected String name;
        protected SubjectDemo subjectDemo;
    
        public ObserverDemo(String name, SubjectDemo subjectDemo) {
            this.name = name;
            this.subjectDemo = subjectDemo;
        }
    
        public abstract void update();
    }
    
    具体通知者

    前台Secretary和老板Boss作为具体通知者,实现Subject接口。这里只给出Secretary类的代码,Boss类与之类似。

    public class Secretary implements SubjectDemo {
        //同事列表
        private List<ObserverDemo> observerDemos = new CopyOnWriteArrayList<>();
        private String action;
    
        @Override
        public void attach(ObserverDemo observerDemo) {
            observerDemos.add(observerDemo);
        }
    
        @Override
        public void detach(ObserverDemo observerDemo) {
            observerDemos.remove(observerDemo);
        }
    
        @Override
        public void notifyObservers() {
            observerDemos.forEach(item -> {
                item.update();
            });
        }
    
        @Override
        public void setAction(String action) {
            this.action = action;
        }
    
        @Override
        public String getAction() {
            return action;
        }
    }
    
    具体观察者
    public class StockObserver extends ObserverDemo {
    
        public StockObserver(String name, SubjectDemo subjectDemo) {
            super(name, subjectDemo);
        }
    
        @Override
        public void update() {
            System.out.println(subjectDemo.getAction()+"\n"+name+"关闭股票行情,继续工作");
        }
    }
    
    public class NBAObserver extends ObserverDemo {
        public NBAObserver(String action, SubjectDemo subjectDemo) {
            super(action, subjectDemo);
        }
            @Override
            public void update () {
                System.out.println(subjectDemo.getAction() + "\n" + name + "关闭直播,继续工作");
            }
        }
    
    前台作为通知者进行通知

    前台作为通知者,通知观察者。这里添加adam和tom到通知列表,并从通知列表中删除了adam,测试没在通知列表中的对象不会收到通知。

    public class TestDemo {
        public static void main(String[] args) {
            //前台为通知者
            Secretary secretary = new Secretary();
    
            StockObserver observer = new StockObserver("adam", secretary);
            NBAObserver observer1 = new NBAObserver("tom", secretary);
            //前台通知
            secretary.attach(observer);
            secretary.attach(observer1);
            //adam没有被前台通知到,所以被老板抓个现行
            secretary.detach(observer);
    
            //老板回来了
            secretary.setAction("小心!Boss回来了!");
            //发通知
            secretary.notifyObservers();
        }
    }
    

    相关文章

      网友评论

          本文标题:观察者模式

          本文链接:https://www.haomeiwen.com/subject/xkiklrtx.html