美文网首页
设计模式——观察者模式

设计模式——观察者模式

作者: TokyoZ | 来源:发表于2018-07-22 21:58 被阅读10次

    观察者模式(Observer),属于行为型模式。又叫发布-订阅(Publish/Subscribe)模式、模型-视图 (Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个 主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

    JDK自带的观察者模式

    JDK内部已经实现了观察者模式,观察者需要实现Observer接口,被观察者需要继承Observable类。

    下面以内容订阅者(观察者)订阅内容发布者(被观察者)的发布内容来举例,当内容发布者发布内容时,会马上将发布内容发送给订阅者去处理。

    1、被观察者WeiboWriter,需要继承Observable基类:

    import java.util.Observable;
    
    public class WeiboWriter extends Observable {   
        
        public void write(String weibo) {
            setChanged();
            notifyObservers(weibo);
        }
        
    }
    

    当内容发布者发布内容时,调用notifyObservers()方法去通知观察者,内容以及发布。
    在调用notifyObservers()之前,需要先调用setChanged()方法,否则将无法发送消息给观察者。

    2、观察者WeiboReader,需要实现Observer接口,复写update()方法:

    import java.util.Observable;
    import java.util.Observer;
    
    public class WeiboReader implements Observer{
    
        @Override
        public void update(Observable o, Object obj) {
            if(obj instanceof String) {
                String objStr = (String) obj;
                System.out.println("推送:" + obj);
            }
        }   
    }
    

    当内容发布者(被观察者)发布内容时,内容订阅者(观察者)会在update()方法内收到消息,并处理。

    3、编写一个sina类,测试:

    public class Sina {
    
        public static void main(String[] args) {
            WeiboWriter writer = new WeiboWriter();
            WeiboReader reader = new WeiboReader();
            writer.addObserver(reader);
            writer.write("周小伦最新专辑,马上上线!");
        }
    }
    

    结果打印:

    推送:周小伦最新专辑,马上上线!
    

    被观察者无法继承Observable的解决办法

    有时候,我们的被观察者由于已经继承其他父类而无法继承Observable时,我们可以采用组合的方式解决这个问题——在被观察者内部创建一个Observable类,来中转发送消息。

    1、新建一个类MyObservable,继承Observable类:

    import java.util.Observable;
    
    public class MyObservable extends Observable{
    
        public synchronized void setChanged() {
            super.setChanged();
        }
    }
    

    需要手动创建一个MyObservable的原因在于,Observable类的setChanged()方法由于protect权限设置,无法在外部类调用,因此我们需要采用如上这种方式扩大其使用权限。

    2、在被观察者内部创建一个MyObservable实例对象,通过MyObservable实例对象来达到发送订阅消息的目的:

    import java.util.Observable;
    import java.util.Observer;
    
    public class WeiboWriter extends JavaWorker {   
        
        private MyObservable observable = new MyObservable();
        
        public void write(String weibo) {
            observable.setChanged();
            observable.notifyObservers(weibo);
        }
        
        public void addObserver(Observer observer) {
            observable.addObserver(observer);
        }
    }
    

    总结

    JDK内部实现的观察者模式实现起来很方便,并且是线程安全的,缺点是被观察者需要继承Observable或者通过其他方式间接继承此类。

    自己实现观察者模式

    这里以公司发工资给员工举例,会计是被观察者,员工是观察者,员工观察会计发工资这个动作,当会计发工资后,员工第一时间得到通知。

    1、编写接口Accounting,模拟发工资的动作:

    public interface Accounting {
        
        public void payOff();
        
        public void addWorker(Worker woker);
        
        public void removeWorker(Worker woker);
    
    }
    

    2、编写Worker接口,模拟员工在拿到工资后的处理:

    public interface Worker {
    
        public void wagaWaga(int salary);
    }
    

    3、编写Boss类,实现Accounting接口(小公司,老板就是会计):

    import java.util.ArrayList;
    import java.util.List;
    
    public class Boss implements Accounting{
    
        private List<Worker> workers;
        
        public Boss() {
            workers = new ArrayList<>();
        }
        
        @Override
        public void payOff() {
            for (int i = 0; i < workers.size(); i++) {
                Worker worker = workers.get(i);
                worker.wagaWaga((i + 1) * 1000);
            }
            
        }
    
        @Override
        public void addWorker(Worker woker) {
            if(!workers.contains(woker)) {
                workers.add(woker);
            }
        }
    
        @Override
        public void removeWorker(Worker woker) {
            if(workers.contains(woker)) {
                workers.remove(woker);
            }
        }
    
    }
    

    4、编写3个员工,JavaWorkerPHPWorkerCWorker,实现Worker接口:

    public class JavaWorker implements Worker{
    
        @Override
        public void wagaWaga(int salary) {
            System.out.println("JavaWorker 本月工资:" + salary);
        }
    
    }
    

    5、编写Company类,测试:

    public class Company {
    
        public static void main(String[] args) {
            Accounting accounting = new Boss();
            
            Worker javaWorker = new JavaWorker();
            Worker phpWorker = new PHPWorker();
            Worker cWorker = new CWorker();
            
            accounting.addWorker(javaWorker);
            accounting.addWorker(phpWorker);
            accounting.addWorker(cWorker);
            
            accounting.payOff();
        }
    }
    

    测试结果:

    JavaWorker 本月工资:1000
    PHPWorker 本月工资:2000
    CWorker 本月工资:3000

    相关文章

      网友评论

          本文标题:设计模式——观察者模式

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