java设计模式之-观察者模式

观察者模式在实际开发应用中很常见。很多的源码用的也很多,例如spring中常见的事件机制就是观察者模式,观察者模式也可以看作发布/订阅模式

 

从实际生活中可以举一些例子:

1:交通信号灯(目标,被观察者)

2:人(观察者,分步行人,骑自行车人,开车人)

人观察信号灯这个目标,如果信号灯发生改变,则人开始根据信号灯的颜色做出反应

分析理解:信号灯改变是一个事件,这个事件该怎么通知出去到行人?人接收到事件改变后根据自己的交通工具做出反应。

解决:信号灯要能通知到每个人,那么这个信号灯必须知道有哪些人在看它。类比,信号灯这个抽象 Light(观察者观察的目标) 必须有一个列表属性  Vector<人> (观察者)(线程同步的列表)

如果Light.changed(),遍历这个Vector,调用<人>doSomeThing(),从而这个人可以对事件改变做出反应

这种设计模式很简单,你可以自己写一个,或者利用jdk提供的Observer(观察者)和Observable(可观察的事物,可以理解成目标的意思)

  • Observer源码
package java.util;

public interface Observer {
   
    void update(Observable o, Object arg);
}

这个就是观察者了,观察者接口中只有一个update方法,参数是一个Observable(目标)和一个arg参数,这个参数类型不限定

这个update什么时候调用呢?我们在上面已经讲过了  “如果Light.changed(),遍历这个Vector,调用<人>doSomeThing(),从而这个人可以对事件改变做出反应”

这个update就是人的doSomeThing(),这个方法是给目标准备的,当目标改变的时候通过update这个方法来让观察者做出反应,既然如此jdk有没有提供目标或者被观察

的事物呢?

  • Observable
package java.util;


public class Observable {
    private boolean changed = false;
//观察者列表
private Vector<Observer> obs; public Observable() { obs = new Vector<>(); } //添加观察者 public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver(Observer o) { obs.removeElement(o); }

public void notifyObservers() { notifyObservers(null); } //通知观察者 public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); }
//添加观察者时需要改变这个状态,否则观察者无法监听到目标改变 protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } public synchronized boolean hasChanged() { return changed; } public synchronized int countObservers() { return obs.size(); } }

先看 

通知观察者notifyObservers() 这个方法,
synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);

方法中有个changed变量,这个变量默认false,该方法将直接返回,所以方法要向下执行到  观察者的update()方法,则setChange()这个方法必须在

notifyObservers()调用之前被调用 ,现在我们来实现这个信号灯作为目标,人作为观察者的观察者模式,

目标信号灯添加观察者人(可以叫注册,也可以叫监听),目标信号灯发生改变时,人接收到信号灯改变时,做出相应的行为动作:

  1. 目标信号灯对象
import java.util.Observable;

public class LightObservable extends Observable {

    public void greenLight() {
        setChanged();
        notifyObservers("绿灯了...");
    }
}

目标信号灯发出路灯信号,该事件发生,但是此时还没有任何人关注到该信号灯的改变(因为上文提到:目标信号灯添加观察者人(可以叫注册,也可以叫监听))

所以我们先要添加关注信号灯的人:

import java.util.Observable;
import java.util.Observer;

public class PasserbyObserver  implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println((String)arg+"我可以过马路了...");
    }
}
import java.util.Observable;
import java.util.Observer;

public class RideManObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println((String)arg+"我可以骑车过马路了!");
    }
}
import java.util.Observable;
import java.util.Observer;

public class DriveManObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println((String)arg+"我可以开车过去了");
    }
}

现在来添加不同的人到目标中(可以叫注册或者监听)

import java.util.Observer;

public class Test {

    public static void main(String[] args) {
        //目标
        LightObservable ob = new LightObservable();
        //步行观察者
        Observer passerbyOb = new PasserbyObserver();
        //骑车人观察者
        Observer rideManOb = new RideManObserver();
        //骑车人观察者
        Observer driverManOb = new DriveManObserver();
        //注册不同观察者
        ob.addObserver(passerbyOb);
        ob.addObserver(rideManOb);
        ob.addObserver(driverManOb);
        ob.greenLight();
    }
}

说明:当目标信号灯中已经存在观察者的时候,现在可以发送路灯事件了

执行后结果:

绿灯了...我可以开车过去了
绿灯了...我可以骑车过马路了!
绿灯了...我可以过马路了...

 

 

自己实现的不同部门给不同员工发送信息,直接贴代码:

/**
 * 公司部门接口
 * @author sky
 *
 */
public interface Dept {
    
    /**公司部门添加指定的员工*/
    public void addEmployee(Employee employeeInterface);
    
    /**公司部门删除指定的员工*/
    public void remEmployee(Employee employeeInterface);
    
    /**公司部门发布消息*/
    public void sendMeetingMessage(String Message);

}
//实现了公司部门的抽象类
public abstract class AbstractDept implements Dept {

    //定义一个员工接口集合
    List<Employee> employeeList = new ArrayList<>();
    
    @Override
    public void addEmployee(Employee employeeInterface) {
        this.employeeList.add(employeeInterface);
    }

    @Override
    public void remEmployee(Employee employeeInterface) {
        if(!CollectionUtils.isEmpty(employeeList)) {
            this.employeeList.remove(employeeInterface);
        }
    }

}
/**
 * 信息部门
 * @author sky
 *
 */
public class InformationDept extends AbstractDept {

    @Override
    public void sendMeetingMessage(String message) {
        for (Employee employeeInterface : employeeList) {
            employeeInterface.recivedMessage(message);
        }
    }

}
/**
 * 财务部门
 * @author sky
 *
 */
public class FinanceDept extends AbstractDept {


    @Override
    public void sendMeetingMessage(String message) {
        for (Employee employeeInterface : employeeList) {
            employeeInterface.recivedSalayMessage(message);
        }
    }

}
//员工接口
public interface Employee {
    
    //员工接收消息
    public void recivedMessage(String message);
    
    //员工接收工资消息
    public void recivedSalayMessage(String message);

}
/**
 * 全体员工
 * @author sky
 *
 */
public class CommonEmployee implements Employee {
    
    public CommonEmployee(String name) {
        super();
        this.name = name;
    }
    
    public CommonEmployee(String name, double salary) {
        super();
        this.name = name;
        this.salary = salary;
    }

    //员工名称
    private String name;
    //员工工资
    private double salary;
    
    
    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public void recivedMessage(String message) {
        System.out.println("通知:"+this.name+message);
    }

    @Override
    public void recivedSalayMessage(String message) {
        System.out.println("通知:"+this.name+":"+this.salary+message);
    }

}
/**
 * 小组领导
 * @author sky
 *
 */
public class GroupLeaderEmployee implements Employee {

    //小组领导名称
    private String name;
    //员工工资
    private double salary;
    
    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public GroupLeaderEmployee(String name) {
        super();
        this.name = name;
    }
    
    public GroupLeaderEmployee(String name, double salary) {
        super();
        this.name = name;
        this.salary = salary;
    }

    @Override
    public void recivedMessage(String message) {
        System.out.println("通知:"+this.name + message);
    }

    @Override
    public void recivedSalayMessage(String message) {
        System.out.println("通知:"+this.name+":"+this.salary + message);
    }

}

测试:

public class TestSendMessage {

    public static void main(String[] args) {
        
        //========================信息部门发布开会消息===========================
        //信息部门
        InformationDept informationDept = new InformationDept();
        //员工组长A、B、C
        GroupLeaderEmployee groupLeaderA = new GroupLeaderEmployee("领导A",3100);
        GroupLeaderEmployee groupLeaderB = new GroupLeaderEmployee("领导B",3099);
        GroupLeaderEmployee groupLeaderC = new GroupLeaderEmployee("领导C",3098);
        //信息部门给组长发送消息
        informationDept.addEmployee(groupLeaderA);
        informationDept.addEmployee(groupLeaderB);
        informationDept.addEmployee(groupLeaderC);
        informationDept.sendMeetingMessage("今天下午3点会议室201组长开会...");
        //信息部门给所有人发送消息
        CommonEmployee employeeA = new CommonEmployee("员工A",2100);
        CommonEmployee employeeB = new CommonEmployee("员工B",2200);
        CommonEmployee employeeC = new CommonEmployee("员工C",2300);
        informationDept.addEmployee(employeeA);
        informationDept.addEmployee(employeeB);
        informationDept.addEmployee(employeeC);
        informationDept.sendMeetingMessage("今天下午5点会议室201全体开会...");
        //=======================财务部门发布所有员工的工资发放通知================
        //财务部门
        FinanceDept financeDept = new FinanceDept();
        //财务部门给所有人发送工资发放通知
        financeDept.addEmployee(employeeA);
        financeDept.addEmployee(employeeB);
        financeDept.addEmployee(employeeC);
        financeDept.addEmployee(groupLeaderA);
        financeDept.addEmployee(groupLeaderB);
        financeDept.addEmployee(groupLeaderC);
        financeDept.sendMeetingMessage("工资已发放,请注意查收!");
    }

}

返回结果:

通知:领导A今天下午3点会议室201组长开会...
通知:领导B今天下午3点会议室201组长开会...
通知:领导C今天下午3点会议室201组长开会...
通知:领导A今天下午5点会议室201全体开会...
通知:领导B今天下午5点会议室201全体开会...
通知:领导C今天下午5点会议室201全体开会...
通知:员工A今天下午5点会议室201全体开会...
通知:员工B今天下午5点会议室201全体开会...
通知:员工C今天下午5点会议室201全体开会...
通知:员工A:2100.0工资已发放,请注意查收!
通知:员工B:2200.0工资已发放,请注意查收!
通知:员工C:2300.0工资已发放,请注意查收!
通知:领导A:3100.0工资已发放,请注意查收!
通知:领导B:3099.0工资已发放,请注意查收!
通知:领导C:3098.0工资已发放,请注意查收!

 

posted @ 2020-05-27 15:46  杨敏86  阅读(487)  评论(0编辑  收藏  举报