【重学设计模式】观察者模式

这是我参与新手入门的第2篇文章。

前言

   使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。同时呢RxJava是基于观察者模式的一种编程模型想要学RxJava首先是需要对观察者模式有一定的了解。

观察者模式介绍

暗中观察.jpeg

   “牵一发而动全身”当一个对象发生改变,其他已登记在案的对象观察到这一改变时做出相应的措施。通过这种方式来达到减少依赖关系,解除耦合。

观察者模式的定义

   定义对象间的一种一对多的以来关系,是的每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

优点:

  • 观察者和被观察者之间是抽象耦合。
  • 增强系统灵活性、可扩展性。

缺点:

  • 我们的程序一般包括一个被观察者,多个观察者。在Java中消息的通知是默认是顺序执行的,一个观察者卡顿会导致系统整体的响应时间延迟。这种情况下,可以考虑使用异步的方式。

观察者UML图

观察者模式 (1).png

ISubject: 抽象主题,也就是被观察者的角色(Observable),它将所有观察者对象的引用保存到容器里,每个主题都可以包含任意数量的观察者,抽象主题提供一个接口,可以增加,删除观察者对象。

ConcreteSubject: 具体主题,在其内部状态发生改变时,给所有注册者发出通知。

ConcreteObserver: 具体的观察者拥有实际的职责,该角色实现观察者所定义的更新接口,以便于在CncreteSubject的状态发生改变时,更新自身状态。

代码实现

实现场景: 张三和李四通过天气预报观察天气,是否要下雨或者是刮风。

被观察者(ConcreteSubject)推送给观察者(Observer)

  1. 首先定义Subject主题接口即被观察者。
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer... observer);
    void notifyObservers(boolean isRain, boolean isWindy);
}
复制代码
  1. 定义观察者超类
public interface Observer {
    void update(boolean isRain, boolean isWindy);
}

复制代码
  1. 天气数据,实际被观察者。实现接口方法,持有一个存放Observer的集合。
public class WeatherData implements Subject {

    private ArrayList<Observer> observerList;

    public WeatherData() {
        this.observerList = new ArrayList<>();
    }

    /***
     * 注册观察者
     * @param observer 观察者
     */
    @Override
    public void registerObserver(Observer observer) {
        observerList.add(observer);
    }

    /***
     * 移除观察者
     * @param Observer...observer  Java 5开始,Java语言对方法参数支持一种新写法,叫可变长度参数列表,
     * 其语法就是类型后跟“…”表示此处接受的参数为0到多个Object类型的对象,或者是一个Object[]
     */
    @Override
    public void removeObserver(Observer... observer) {
        if(observer.length == 0){
            observerList.removeAll(observerList);
        }else {
            for (Observer observers : observer) {
                observerList.remove(observers);
            }
        }
        System.out.println("observerList size is " + observerList.size());
    }

    /**
     * 通知所有观察者数据改变
     * @param isRain
     * @param isWindy
     */
    @Override
    public void notifyObservers(boolean isRain, boolean isWindy) {
        for (Observer observer : observerList) {
            observer.update(isRain, isWindy);
        }
    }
    
    public void onChange(boolean isRain, boolean isWindy){
        notifyObservers(isRain, isWindy);
    }
}
复制代码
  1. 定义实体类和工具类
public class User implements Observer {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public void update(boolean isRain, boolean isWindy) {
        String name = getName();
        System.out.println("notify " + name + " isRain -> " + isRain + ", isWindy -> " + isWindy );
        switch (getName()){
            case "Zhangsan":
                //做自己要做的事情
                break;
            case "Lisi":
                //TODO
                break;
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age && Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
复制代码
public abstract class SingletonUtils<T> {
    private T instance;

    public abstract T create();

    public final T getInstance(){

        if(Objects.isNull(instance)){
            synchronized (this){
                if(Objects.isNull(instance)) instance = create();
            }
        }
        return instance;
    }
}
复制代码
  1. 定义客户端
public class Client {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        weatherData.registerObserver(new SingletonUtils<User>() {
            @Override
            public User create() {
                User user = new User();
                user.setName("Zhangsan");
                return user;
            }
        }.getInstance());
        weatherData.registerObserver(new SingletonUtils<User>() {
            @Override
            public User create() {
                User user = new User();
                user.setName("Lisi");
                return user;
            }
        }.getInstance());
        weatherData.onChange(true,false);
        weatherData.removeObserver();
    }
}
复制代码

输出:使用完记得将存放Observer的容器清空。

image.png

由观察者(Observer)主动去拉数据

  1. 天气数据,实际被观察者。实现Observer(使用JDK提供的工具类,java.util.Observable)接口方法。
import java.util.Observable;
import java.util.Observer;

public class WeatherDatas extends Observable {

    boolean isRain;
    boolean isWindy;

    public WeatherDatas() {
    }

    public boolean getRain() {
        return isRain;
    }

    public boolean getWindy() {
        return isWindy;
    }

    @Override
    public synchronized void addObserver(Observer o) {
        super.addObserver(o);
    }

    @Override
    public void notifyObservers() {
        super.notifyObservers();
    }

    @Override
    protected synchronized void setChanged() {
        super.setChanged();
    }

    public void onChange(boolean isRain, boolean isWindy){
        this.isRain = isRain;
        this.isWindy = isWindy;
        //一定要先调用setChanged,notifyObservers中对changed变量做了判断。
        setChanged();
        notifyObservers();
    }
}
复制代码
  1. 定义观察者子类,实现java.util.Observer
import java.util.Observable;
import java.util.Observer;

public class Users implements Observer {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public void update(Observable o, Object arg) {
        if(o instanceof WeatherDatas){
            WeatherDatas weatherDatas = (WeatherDatas) o;
            System.out.println("notify " + name + " isRain -> " + weatherDatas.getRain() +
                    ", isWindy -> " +  weatherDatas.getWindy());
            switch (getName()){
                case "Zhangsan":
                    //TODO
                    break;
                case "Lisi":
                    //TODO
                    break;
            }
        }
    }
}
复制代码

在通知所有观察者前一定要先调用setChange,源码中可以看到,如果change为false,会直接return,不在通知各观察者。

image.png

image.png

结尾

   像ListView常用的Adapter.notifityDataSetChanged,RxJava中观察者模式都是必不可少的,灵活性强,耦合性低并且是Android源码中优秀运用的典范。针不错,今天有学到了一个设计模式。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享