观察者模式(行为型模式)

目录

1.观察者通用代码

2.JDK实现

3.需求代码

3.1观察者模式实现

3.2异步模式优化

4.观察者模式优点与缺点

4.1 优点:

4.2 缺点

5.观察者模式应用场景

6.注意事项


        观察者模式(Observer Design Pattern):在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会得到通知并自动更新。也叫发布订阅模式,能够很好的解耦一个对象改变,自动改变另一个对象这种情况。

1. Subject 被观察者

        定义被观察者必须实现的职责, 它必须能够动态地增加、 取消观察者。 它一般是抽象类或者是实现类, 仅仅完成作为被观察者必须实现的职责: 管理观察者并通知观察者。

2. Observer观察者

        观察者接收到消息后, 即进行update(更新方法) 操作, 对接收到的信息进行处理。

3. ConcreteSubject具体的被观察者

        定义被观察者自己的业务逻辑, 同时定义对哪些事件进行通知。

4. ConcreteObserver具体的观察者

        每个观察在接收到消息后的处理反应是不同, 各个观察者有自己的处理逻辑。

1.观察者通用代码

/**
 * 观察者
 */
public interface Observer {
    // 更新方法
    void update();
}
/**
 * 具体观察者
 */
public class ConcreteObserver implements Observer{
    @Override
    public void update() {
        System.out.println("接受到信息,并进行处理");
    }
}
/**
 * 被观察者
 */
public abstract class Subject {
    // 定义一个被观察者数组
    private List<Observer> obsList = new ArrayList<>();

    // 增加一个观察者
    public void addObserver(Observer observer){
        obsList.add(observer);
    }

    // 删除一个观察者
    public void delObserver(Observer observer){
        obsList.remove(observer);
    }

    // 通知所有观察者
    public void notifyObservers(){
        for (Observer observer : obsList){
            observer.update();
        }
    }
}
/**
 * 具体被观察者
 */
public class ConcreteSubject extends Subject{
    // 具体的业务
    public void doSomething(){
        super.notifyObservers();
    }
}
public class ObserverClient {

    public static void main(String[] args) {
        // 创建一个被观察者
        ConcreteSubject subject = new ConcreteSubject();
        // 定义一个观察者
        Observer observer = new ConcreteObserver();
        // 观察者观察被观察者
        subject.addObserver(observer);
        subject.doSomething();
    }
}

2.JDK实现

        在 JDK 的 java.util 包下,已经为我们提供了观察者模式的抽象实现。

观察者 java.util.Observer

创建一个类实现Observer接口

被观察者 java.util.Observable

创建一个类继承Observable类

3.需求代码

用户进行注册,注册完成之后,会发一封欢迎邮件。

public class UserController {

    public void register(String userName, String passWord){
        // 1、根据用户名密码保存在数据库
        Long userId = saveUser(userName, passWord);
        // 2、如果上一步有结果则发送一封欢迎邮件
        if(userId != null){
            Mail.sendEmail(userId);
        }
    }


    public Long saveUser(String userName, String passWord){
        return 1L;
    }
}

        上面的注册操作实现了两件事,注册和发送邮件,很明显违反了单一职责原则,但假设这个注册需求是不是经常变动的,这样写也没有什么问题,但是假如需求变动,比如不仅要发送邮件,还得发送短信,那还这样写,那register接口会变得很复杂。

那应该如何简化呢?没错,就是观察者模式。

3.1观察者模式实现

        这里直接套用JDK实现。

import java.util.Observable;

/**
 * 用户登录——被观察者
 */
public class UserControllerObservable extends Observable {

    public void register(String userName, String passWord){
        // 1、根据用户名密码保存在数据库
        Long userId = saveUser(userName, passWord);
        // 2、如果上一步有结果则通知所有观察者
        if(userId != null){
            super.setChanged();
            super.notifyObservers(userName);
        }
    }

    public Long saveUser(String userName, String passWord){
        return 1L;
    }

}
import java.util.Observable;
import java.util.Observer;

/**
 * 发送邮件——观察者
 */
public class MailObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("发送邮件:" + arg + "欢迎你");
    }
}
/**
 * 发送手机短信——观察者
 */
public class SMSObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("发送短信:" + arg + "欢迎你");
    }
}

        通过观察者模式改写后,后面用户注册,就算在增加别的操作,我们也只需要增加一个观察者即可,而注册操作register 不会有任何改动。

测试:

public static void main(String[] args) {
    // 观察者
    UserControllerObservable userControllerObservable = new UserControllerObservable();
    //被观察者
    MailObserver mailObserver = new MailObserver();
    SMSObserver smsObserver = new SMSObserver();
    // 增加到观察列表
    userControllerObservable.addObserver(mailObserver);
    userControllerObservable.addObserver(smsObserver);
    // 调用方法 干活
    userControllerObservable.register("jsl","123456");
}

3.2异步模式优化

        注册之后进行的两步操作:发送邮件和发送短信,上面我们通过观察者模式改写之后,虽然流程很清晰,但是我们发现是顺序执行的,但其实这两步操作没有先后顺序,于是,我们可以改成异步模式,增加执行效率。

/**
 * 发送邮件——观察者
 */
public class MailObserver implements Observer {
    
    private Executor executor = Executors.newFixedThreadPool(2);

    @Override
    public void update(Observable o, Object arg) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("发送邮件:" + arg + "欢迎你");
            }
        });

    }
}

4.观察者模式优点与缺点

4.1 优点:

(1)  观察者和被观察者之间是抽象耦合

        不管是增加观察者还是被观察者都非常容易扩展,在系统扩展方面会得心应手。

(2)  建立一套触发机制

        被观察者变化引起观察者自动变化。但是需要注意的是,一个被观察者,多个观察者,Java的消息通知默认是顺序执行的,如果一个观察者卡住,会导致整个流程卡住,这就是同步阻塞。所以实际开发中没有先后顺序的考虑使用异步,异步非阻塞除了能够实现代码解耦,还能充分利用硬件资源,提高代码的执行效率。另外还有进程间的观察者模式,通常基于消息队列来实现,用于实现不同进程间的观察者和被观察者之间的交互。

4.2 缺点

(1)  如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

(2)  如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

(3)  观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

5.观察者模式应用场景

  1. 关联行为场景。
  2. 事件多级触发场景。
  3. 跨系统的消息交换场景, 如消息队列的处理机制。

6.注意事项

  1. JAVA 中已经有了对观察者模式的支持类。
  2. 避免循环引用。
  3. 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值