设计模式之观察者模式

读书笔记:headfirst 设计模式 ,大话设计模式,相关技术博客等


观察者模式

概念:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并且自动更新

  • 观察者模式又称发布/订阅(publish/subscribe)模式
  • 观察者模式定义了对象之间的一对多关系
  • 主题(可观察者)用一个共同的接口来更新观察者
  • 观察者和可观察者之间用松耦合方式结合,双方不知道对方的细节
  • 使用观察者模式,可以从被观察者处push推或pull拉数据

观察者模式结构图

代码案例

老师发布作业,老师的每个学生会收到作业通知


// 观察者模式案例测试
public class ObserverTest {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        // 订阅
        Student s1 = new Student("xiaoMing", teacher);
        Student s2 = new Student("xiaoZhang", teacher);
        Student s3 = new Student("xiaoLi", teacher);
        // 发布通知
        teacher.setHomework("数学课后习题");
        teacher.setHomework("语文课前预习");
    }
}

结果:
老师布置作业:数学课后习题
学生_xiaoMing_收到作业:数学课后习题
学生_xiaoZhang_收到作业:数学课后习题
学生_xiaoLi_收到作业:数学课后习题
老师布置作业:语文课前预习
学生_xiaoMing_收到作业:语文课前预习
学生_xiaoZhang_收到作业:语文课前预习
学生_xiaoLi_收到作业:语文课前预习


// 观察者
public interface Observer {
    void update(String info);
}

// 主题(被观察者)
public interface Subject {
    // 添加观察者
    void addObserver(Observer observer);
    // 移除观察者
    void removeObserver(Observer observer);
    // 通知所有观察者
    void notifyObserver();
}

// 观察者 学生实现
public class Student implements Observer {
    
    private String name;
    // 保存被观察者subject引用,以后可以方便取消订阅
    private Teacher teacher;

    public Student(String name,Teacher teacher) {
        this.name =name;
        this.teacher=teacher;
        // 建立学生添加到被观察者中
        teacher.addObserver(this);
    }

    @Override
    public void update(String info) {
        System.out.println("学生_"+name+"_收到作业:"+info);
    }

}

// 被观察者 老师 实现
public class Teacher implements Subject {
    // 存放观察者
    private List observers = new ArrayList();
    // 记录作业
    private String homework;

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int indexOf = observers.indexOf(observer);
        if (indexOf>=0) {
            observers.remove(indexOf);
        }
    }

    @Override
    public void notifyObserver() {
        for (Observer observer : observers) {
            observer.update(homework);
        }
    }
    
    // 布置作业,最后调用notifyObserver(),通知所有被观察者更新
    public void setHomework(String homework) {
        this.homework = homework;
        System.out.println("老师布置作业:"+homework);
        notifyObserver();
    }

}

java内置的观察者模式

使用java.util包的Observer接口与Observable类


// 观察者
public class Student implements Observer {
    
    private String name;
    private Observable observable;
    
    public Student(String name,Observable observable) {
        this.name =name;
        this.observable=observable;
        // 建立学生添加到观察者中
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        Teacher teacher=(Teacher) o;
        // 拉取数据
        System.out.println("PULL:学生_"+name+"_收到作业:"+teacher.getHomework());
        // 接收推送数据
        System.out.println("PUSH:学生_"+name+"_收到作业:"+arg.toString());
    }

}

// 被观察者
public class Teacher extends Observable {
    // 记录作业
    private String homework;
    
    // 布置作业,最后调用notifyObserver(),通知所有被观察者更新
    public void setHomework(String homework) {
        this.homework = homework;
        System.out.println("老师布置作业:"+homework);
        //PS:重点  需要更改状态 ,好让notify知道当它被调用时应该更新观察者 
        //这样设计更有弹性,可以选择适当的通知观察者 clearChanged()将状态设置回false,hasChanged()获取当前状态
        setChanged();
        // 推送数据(作业)
        notifyObservers(homework);
    }
    // 用于观察者拉取数据
    public String getHomework() {
        return homework;
    }
}

// 测试
public class ObserverTest {
    
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Student s1 = new Student("学生A", teacher);
        Student s2 = new Student("学生B", teacher);
        teacher.setHomework("作业1");
        teacher.setHomework("作业2");
    }
}

结果:
老师布置作业:作业1
PULL:学生_学生B_收到作业:作业1
PUSH:学生_学生B_收到作业:作业1
PULL:学生_学生A_收到作业:作业1
PUSH:学生_学生A_收到作业:作业1
老师布置作业:作业2
PULL:学生_学生B_收到作业:作业2
PUSH:学生_学生B_收到作业:作业2
PULL:学生_学生A_收到作业:作业2
PUSH:学生_学生A_收到作业:作业2

PS: 注意不可以依赖观察者的特定通知次序,一旦被观察者的实现改变,通知次序可能就会发生改变

内置Observable缺陷

  • 可观察者是一个类,而不是接口,限制了复用潜力
  • setChanged()方法为protected,无法创建实例组合到自定义对象中,只能继承

你可能感兴趣的:(笔记,读书笔记,设计模式,观察者模式,headfirst,大话设计模式)