详解设计模式 观察者模式

2,167 阅读5分钟

观察者模式

观察者模式属于行为型模式

定义:

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

模式类图

角色:

  1. 被观察者:Subject定义一个被观察者必须实现职责,包括动态增加,删除,通知观察者
  2. 观察者:Observer接受到观察者修改消息,执行自身逻辑
  3. 具体观察者:ConctreteSubject继承Subject,拥有自己的业务逻辑,具有被观察者基本功能,对某些事件进行通知
  4. 具体的观察者:ConcreteObserver具体观察者,在接受到被观察者变更消息后,进行各自业务处理

优点

  1. 观察者和被观察者之间是抽象耦合,容易拓展
  2. 通过触发机制可以创建成一种链式触发机制,形成多级触发

缺点

  1. 执行效率

    当通知观察者是顺序执行时,需要考虑整个观察者列表的数量,对整个通知事件执行效率的影响,可以考虑使用异步通知,同时尽量避免多级触发事件

  2. 循环依赖

    当观察者和被观察之间形成循环依赖,会导致循环调用,比如A改变通知B,B改变通知C,C改变通知A,注意避免循环依赖的发生

模式代码实现

以用户修改密码为例,当用户密码改变后,使用短信和邮件对用户进行消息提醒

源码地址:https://github.com/mingyuHub/design-patterns

被观察者接口

Subjectable 定义被观察者基本功能

/**
 * @author: chenmingyu
 * @date: 2019/3/15 13:44
 * @description: 被观察者接口
 */

public interface Subjectable {

    /**
     * 增加观察者
     */

    void addObserver(Observerable observer);

    /**
     * 移除观察者
     */

    void removeObserver(Observerable observer);

    /**
     * 通知观察者
     */

    void notifyObserver(Object object);
}
被观察者抽象类

AbstractSubject被观察者类的公共父类,实现了被观察者基本功能的实现,使用Vector为观察者列表

/**
 * @author: chenmingyu
 * @date: 2019/3/15 11:24
 * @description: 被观察者抽象类
 */

public abstract class AbstractSubject implements Subjectable{

    /**
     * 观察者列表
     */

    private Vector<Observerable> observers = new Vector();

    @Override
    public void addObserver(Observerable observer){
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observerable observer){
        observers.add(observer);
    }

    @Override
    public void notifyObserver(Object object){
        observers.forEach(observer->{
            observer.update(object);
        });
    }
}
被观察者类

UserInfo实现AbstractSubject

/**
 * @author: chenmingyu
 * @date: 2019/3/15 13:50
 * @description: 被观察者
 */

@Data
public class UserInfo extends AbstractSubject{

    /**
     * 昵称
     */

    private String nickName;
    /**
     * 密码
     */

    private String password;

    /**
     * 修改密码
     * @param password
     */

    public void updatePassword(String password){
        this.password = password;
        this.notifyObserver(password);
    }

    public UserInfo(String nickName, String password) {
        this.nickName = nickName;
        this.password = password;
    }
}
观察者接口
/**
 * @author: chenmingyu
 * @date: 2019/3/15 13:40
 * @description: 观察者
 */

public interface Observerable {

    /**
     * 被观察者变化触发事件
     */

    void update(Object object);
}
具体观察者

SmsObserver 接收到被观察者密码变更,发送短信提醒

/**
 * @author: chenmingyu
 * @date: 2019/3/15 13:56
 * @description: 短信观察者
 */

public class SmsObserver implements Observerable {

    @Override
    public void update(Object object) {
        if(null == object){
            return;
        }
        System.out.println("短信观察者");
        System.out.println("短信发送提醒:密码更改为:"+object.toString());
    }
}

EmailObserver 接收到被观察者密码变更,发送邮件提醒

/**
 * @author: chenmingyu
 * @date: 2019/3/15 13:54
 * @description: 邮件观察者
 */

public class EmailObserver implements Observerable{

    @Override
    public void update(Object object) {
        if(null == object){
            return;
        }
        System.out.println("邮件观察者");
        System.out.println("邮件发送提醒:密码更改为:"+object.toString());
    }
}
验证
public static void main(String[] args) {

    UserInfo userInfo = new UserInfo("麻辣香锅","malaxiangguo");

    SmsObserver smsObserver = new SmsObserver();
    EmailObserver emailObserver = new EmailObserver();

    userInfo.addObserver(smsObserver);
    userInfo.addObserver(emailObserver);

    userInfo.updatePassword("mlxg");
}
输出
短信观察者
短信发送提醒:密码更改为:mlxg
邮件观察者
邮件发送提醒:密码更改为:mlxg

SmsObserverEmailObserver观察到UserInfo用户麻辣香锅更改密码为mlxg