观察者模式

简介: 观察者模式

什么是观察者模式



观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。


  对于观察者模式而言,肯定有观察者和被观察者之分。比如在一个目录下建立一个文件,这时系统会通知目录管理器增加目录,并通知磁盘减少空间,在这里,文件就是观察者,目录管理器和磁盘就是被观察者。


  观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:


image.png

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

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();
    }
}



相关文章
|
6月前
|
设计模式 消息中间件 Java
观察者模式
观察者模式
52 1
|
6月前
|
C++
【C++】—— 观察者模式
【C++】—— 观察者模式
|
6月前
|
设计模式 JavaScript 开发者
详细讲解什么是观察者模式
详细讲解什么是观察者模式
|
关系型数据库 API
观察者模式解读
观察者模式解读
|
6月前
行为型 观察者模式(发布订阅)
行为型 观察者模式(发布订阅)
39 0
|
6月前
|
设计模式 Java
【观察者模式】 ——每天一点小知识
【观察者模式】 ——每天一点小知识
5 # 观察者模式
5 # 观察者模式
36 0
|
设计模式 存储
设计模式-观察者模式(Observer)
设计模式-观察者模式(Observer)
96 0
|
设计模式
观察者模式(上)
观察者模式(上)
82 0
|
XML 设计模式 Java
观察者模式(下)
观察者模式(下)
61 0