设计模式——观察者模式

2018-07-22  本文已影响10人  TokyoZ

观察者模式(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
上一篇下一篇

猜你喜欢

热点阅读