美文网首页
【设计模式】2、行为型——观察者模式

【设计模式】2、行为型——观察者模式

作者: _Mitch | 来源:发表于2018-01-29 15:00 被阅读0次

观察者模式为对象间建立了一个一对多的依赖关系,一个被观察的对象对应多个观察它的对象,当被观察的对象做出动作时,观察它的多个对象会得到通知,执行相应的逻辑。所以观察者模式最核心的就是观察者和观察目标,以及他们之间的依赖关系。接下来,我们慢慢阐述。

一、应用场景

当一个对象执行一个操作时,想要让一个或多个对象也做出对应的动作,进行一个联动的时候,可以考虑使用这个设计模式。
比如:在我上小学的时候,我们的上课铃都是靠老师手动敲的,老师敲上课铃时,所有的同学都应该去上课了,敲下课铃时,大家又快乐的玩耍。这就是一个典型的观察者和观察目标的关系,在这里,学生作为观察者对象,有许多个,有时候有的同学也会请假有事不在学校,这个数量是不确定的。敲铃的老师作为观察目标对象,所有的同学都会去监听这个老师是否敲了铃铛,当老师敲铃,铃响了才会进入上/下课状态。下面我们用代码来实现打铃上下课的问题。

二、实际应用

为了拓展性,会为学生和老师分别定义一个统一的接口或者抽象类Student和Teacher,Student作为抽象观察者,定义一些公共的方法,一些具体的操作由实现类或者子类实现,如上课下课等。Teacher作为抽象观察目标,当老师在打铃时若要能通知到学生,并且让学生执行相应的逻辑,那么老师肯定需要持有学生的引用,这里我们用CopyOnWriteArrayList来保存所有的学生对象,并提供相应的添加和删除学生的方法,用于报名和请假。

Student.java

/**
 * Created by mitch on 2018/1/29.
 */
public interface Student {
    void startClass();
    void endClass();
}

Teacher.java

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Created by mitch on 2018/1/29.
 */
abstract class Teacher {
    protected List<Student> students = new CopyOnWriteArrayList<Student>();

    /**
     * 学生报名
     *
     * @param student
     */
    public void addStudent(Student student){
        students.add(student);
    }

    /**
     * 由于请假等原因,移除掉不需要听铃声的同学
     *
     * @param student
     */
    public void removeStudent(Student student){
        students.remove(student);
    }

    /**
     *打上课铃
     *
     */
    public abstract void classBeginRing();

    /**
     * 打下课铃
     */
    public abstract void classEndRing();
}

下面是学生和老师的具体实现类,分别实现上课下课的方法:
PrimaryStudent.java


/**
 *
 * Created by mitch on 2018/1/29.
 */
public class PrimaryStudent implements Student{
    private String name;
    private String state;

    public PrimaryStudent(String name) {
        this.name = name;
    }

    @Override
    public void startClass() {
        this.state = "上课";
        System.out.println(String.format("[%s]同学听到上课铃声,准备认真学习,状态变为[%s]",name,state));
    }

    @Override
    public void endClass() {
        this.state = "下课";
        System.out.println(String.format("[%s]同学听到下课铃声,嗨起来,状态变为[%s]",name,state));
    }

    /**
     * 重写equals方法,删除的时候以name为准
     *
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o) {
        if(!(o instanceof PrimaryStudent)){
            return false;
        }
        return this.name.equals(((PrimaryStudent) o).getName());
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

RingTeacher.java

/**
 * Created by mitch on 2018/1/29.
 */
public class RingTeacher extends Teacher{
    private String name;

    public RingTeacher(String name) {
        this.name = name;
    }

    @Override
    public void classBeginRing() {
        System.out.println(String.format("上课啦![%s]老师打上课铃了",name));
        for(Student student : students){
            student.startClass();
        }
    }

    @Override
    public void classEndRing() {
        System.out.println(String.format("下课啦![%s]老师打下课铃了",name));
        for(Student student : students){
            student.endClass();
        }
    }
}

客户端Main.java

/**
 * Created by mitch on 2018/1/29.
 */
public class Main {
    public static Teacher teacher = new RingTeacher("小红");
    public static void main(String[] args) {
        init();
        //小明请假了
        teacher.removeStudent(new PrimaryStudent("小明"));
        //打上课铃
        teacher.classBeginRing();
        //打下课铃
        teacher.classEndRing();

    }

    /**
     *
     * 初始化学生
     */
    private static void init() {
        teacher.addStudent(new PrimaryStudent("小明"));
        teacher.addStudent(new PrimaryStudent("张三"));
        teacher.addStudent(new PrimaryStudent("李四"));
        teacher.addStudent(new PrimaryStudent("王五"));
        teacher.addStudent(new PrimaryStudent("赵六"));
        teacher.addStudent(new PrimaryStudent("韩梅梅"));
        teacher.addStudent(new PrimaryStudent("李雷"));
    }
}

最后得到运行结果:


图一 运行结果

从运行结果可以看出,因为小明请假了,从学生列表中移除,所以只有除了小明以外的所有学生都听到了铃声,并且切换为上课状态。

三、总结

观察者模式是一个非常经典的设计模式,又称作“订阅-发布模式”,它可以完成类似广播的功能,但是又使观察者和观察目标实现了解耦,当新增和删除观察者使可以不用修改观察目标的代码,有良好的扩展性,在一些优秀的开源项目里使用的频率也很高,比如Tomcat的Catalina的生命周期也是使用的观察者模式来监听的。所以,如果有类似对象联动或者广播等场景时,考虑下观察者模式吧。

PS:上述的例子中,学生和老师的实例化,可以用数据库或者xml利用反射或者Spring框架进行注入,减少代码侵入性,读者不妨试试。

相关文章

网友评论

      本文标题:【设计模式】2、行为型——观察者模式

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