设计模式学习:观察者模式

1. 何为观察者模式?

百度百科:
观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主题是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。

博主理解:当被观察者的状态发生改变时,自动的通知其他的观察者
举个栗子:一个学生在学校里学习,对于学生的家长来说,他们最关心的是学生的成绩,他们希望当孩子的成绩发生改变时,可以及时的通知,进而采取对孩子是奖励或者进行批评教育等行为。
上述的栗子中:
被观察者:学生
被观察者的主要内容:成绩
观察者:家长
需求:当学生的成绩发生改变,家长可以及时被通知,然后根据成绩采取不同的策略
我们如何去解决这个问题呢?如果当观察者突然增多,比如爷爷奶奶也想及时了解到学生的成绩,如何通过简单的方式去解决呢?
解决方案:

  • 笨的方案:让家长每 1ms 去查询一下学生的成绩,如果发生变化,就对应采取相应的策略
  • 聪明的方案:采用观察者模式,当被观察者的成绩发生改变时,自动的通知其他的观察者

2. 如何实现呢?

2.1 自己编写代码:

UML 图我就不画了,不会画,哈哈(*^_^*),直接上代码!!!

2.1.1 主题接口

public interface Subject {

    /**
     * 添加观察者
     * @param observer 观察者
     */
    void addObserver(Observer observer);

    /**
     * 删除观察者
     * @param observer 观察者
     */
    void deleteObserver(Observer observer);

    /**
     * 通知所有的观察者
     */
    void notifyObservers();
}

2.1.2 观察者接口

public interface Observer {
    /**
     * 更新方法
     * @param observedSubject 被观察的主题对象
     * @param arg 传递的参数
     */
    void update(Subject observedSubject, Object arg);
}

2.1.3 被观察者学生类

public class StudentSubject implements Subject{

    /**
     * 关键集合:保存所有观察者实例对象
     */
    private List<Observer> observerList;

    /**
     * 学生成绩
     */
    private float score;

    public StudentSubject() {
        this.observerList = new ArrayList<>(20);
    }

    public void changeScore(float score) {
        this.score = score;
        notifyObservers();
    }

    @Override
    public void addObserver(Observer observer) {
        if (!observerList.contains(observer)) {
            observerList.add(observer);
        }
    }

    @Override
    public void deleteObserver(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observerList) {
            observer.update(this, score);
        }
    }
}

2.1.4 父亲观察者类

public class FatherObserver implements Observer{

    @Override
    public void update(Subject observedSubject, Object arg) {
        if (observedSubject instanceof StudentSubject) {
            float score = Float.parseFloat(arg.toString());
            if (score >= 60) {
                System.out.println("父亲:孩子这次考的还行!成绩:" + score);
            }else {
                System.out.println("父亲:气死老子了!成绩:" + score);
            }
        }
    }
}

2.1.5 母亲观察者

public class MotherObserver implements Observer {
    @Override
    public void update(Subject observedSubject, Object arg) {
        if (observedSubject instanceof StudentSubject) {
            float score = Float.parseFloat(arg.toString());
            if (score >= 60) {
                System.out.println("母亲:孩子这次考的还行!成绩:" + score);
            }else {
                System.out.println("母亲:看来不打不行了!成绩:" + score);
            }
        }
    }
}

2.1.6 测试

public class Test {
    public static void main(String[] args) {
        StudentSubject studentSubject = new StudentSubject();
        FatherObserver fatherObserver = new FatherObserver();
        MotherObserver motherObserver = new MotherObserver();
        studentSubject.addObserver(fatherObserver);
        studentSubject.addObserver(motherObserver);
        studentSubject.changeScore(59);

        // 父亲出差了,暂时不观察孩子了
        studentSubject.deleteObserver(fatherObserver);
        studentSubject.changeScore(80);
    }
}

2.1.7 测试结果

如果还想加入爷爷奶奶他们作为观察者,就分别创建爷爷奶奶的观察者类,然后加入到学生观察者集合里 studentSubject.addObserver(xxx);

2.2 使用 Java 自带工具类:

Java 自带的已经实现了观察者模式的工具类,现在我们看一下,如何用 Java 自带的工具类,写上面这个案例

2.2.1 首先还是创建 StudentSubject 被观察者类,注意,这次是不一样的了!!!

注意:学生主题类直接继承 java.util.Observable 父类

public class StudentSubject extends Observable {

    /**
     * 学生成绩
     */
    private float score;

    public void changeScore(float score) {
        this.score = score;
        setChanged();
        notifyObservers(score);
    }
}

2.2.2 创建父亲观察者

注意:父亲观察者是实现了 java.util.Observer 类,不是上面自定义的 Observer 类了!!!

public class FatherObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof StudentSubject) {
            float score = Float.parseFloat(arg.toString());
            if (score >= 60) {
                System.out.println("父亲:孩子这次考的还行!成绩:" + score);
            }else {
                System.out.println("父亲:气死老子了!成绩:" + score);
            }
        }
    }
}

2.2.3 创建母亲观察者

注意:母亲观察者是实现了 java.util.Observer 类,不是上面自定义的 Observer 类了!!!

public class MotherObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof StudentSubject) {
            float score = Float.parseFloat(arg.toString());
            if (score >= 60) {
                System.out.println("母亲:孩子这次考的还行!成绩:" + score);
            }else {
                System.out.println("母亲:看来不打不行了!成绩:" + score);
            }
        }
    }
}

2.2.4 测试

public class Test {
    public static void main(String[] args) {
        StudentSubject studentSubject = new StudentSubject();
        FatherObserver fatherObserver = new FatherObserver();
        MotherObserver motherObserver = new MotherObserver();
        studentSubject.addObserver(fatherObserver);
        studentSubject.addObserver(motherObserver);
        studentSubject.changeScore(59);

        // 父亲出差了,暂时不观察孩子了
        studentSubject.deleteObserver(fatherObserver);
        studentSubject.changeScore(80);
    }
}

2.2.5 测试截图

注意点:在被观察者通知其他的观察者前要先执行 setChanged(); 方法

至于为什么?咱们看一下源码就知道了,源码是这样的:

 

setChanged(); 是将 changed 状态改为 true

我们现在看一下,他是如何通知其他的观察者的:

通知其他观察者前要检查 changed 状态,如果为 true 则接着下面的代码走,进行通知,如果为 false 就直接返回!

而且细心的读者能看到 clearChanged(); 这个方法是当 changed 为 true 的时候,在将 changed 赋值为 false,这下明白了吧,如果要进行通知其他的观察者时,首先要调用 setChanged(); 方法,改变父类的 changed 状态为 true

3. 有哪些应用呢?

我现在了解到的,事件监听机制:就是在按钮上绑定一个监听器,当按钮按下的时候,会触发事件,然后执行自定义的处理事件代码,这个实现原理就是使用了观察者模式,其他的还在摸索中,本文到这里也就结束了,如果你们有什么意见可以在下面进行评论,我会一一作出回复,共同进步,加油(●'◡'●)!!!

发布了92 篇原创文章 · 获赞 23 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/assiduous_me/article/details/101692599
今日推荐