zoukankan      html  css  js  c++  java
  • 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工资已发放,请注意查收!
  • 相关阅读:
    Markdown快捷笔记
    Linux常用命令
    Git使用
    HTML
    JavaScript-笔记2
    AngularJS-笔记2
    AngularJS-笔记1
    JQuery-笔记
    设置DataGridView的某个单元格为ComboBox
    记录文件浏览历史路径
  • 原文地址:https://www.cnblogs.com/yangmin86/p/12973537.html
Copyright © 2011-2022 走看看