观察者模式——Observer

案例展示——Observer怎么用?

 观察者模式是一种非常通用的模式,以至于JDK都整合了这个设计模式,将其开放成编程接口供程序员使用:java.util.Observable和java.util.Observer。程序员只要实现这两个接口就能轻松使用观察者模式。现在我们先来说说原生的观察者模式是什么样的、怎么去使用这个设计模式。

 假设有这样一种场景:想要升职,除了工作兢兢业业之外,还需要学会察言观色,从领导的一言一行中体会深意。领导有什么行动,自己也要做出相应改变,这叫顺势而为。如何通过编程来表达呢,看下面的类图:

image

类图元素分析:

  • ILeader接口:通用的领导接口,定义一组通用的方法,这些方法就是引发观察者进行观察的发生器。例如:下达命令(order)、回家(goHome)

  • Leader类:实现了ILeader接口和Observable接口

  • Observable接口:被观察者的通用接口,定义了一组方法:添加观察者、删除观察者和通知所有的观察者。所有实现了该接口的类都会被观察者观察

  • Observer接口:观察者接口,定义了一个方法:update(),该方法会应被观察者的行为变化而做出相应动作。所有实现了该接口的类都是观察者

下面是具体的代码实现:

// 被观察者接口
public interface Observable {
    // 增加一个观察者
    public void addObserver(Observer observer);
    // 删除一个观察者
    public void deleteObserver(Observer observer);
    // 发生改变,通知观察者
    public void notifyObservers(String context);
}

// 观察者接口
public interface Observer {
    // 发现被观察者有变化,需要采取行动
    public void update(String context);
}

// 领导接口
public interface ILeader {
    // 领导下命令
    public void order();
    // 领导回家
    public void goHome();
}

// 领导类
public class Leader implements ILeader, Observable {

    // 定义一个变长数组,用于存放所有的观察者
    private ArrayList<Observer> list = new ArrayList<Observer>(16);

    // 领导下命令
    public void order() {
        System.out.println("领导下命令了!");
        // 通知所有观察者
        this.notifyObservers("领导下命令了!");
    }

    // 领导回家
    public void goHome() {
        System.out.println("领导要回家了!");
        // 通知所有观察者
        this.notifyObservers("领导要回家了!");
    }

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

    // 删除一个观察者
    public void deleteObserver(Observer observer) {
        this.list.remove(observer);
    }

    // 通知所有的观察者
    public void notifyObservers(String context) {
        for (Observer observer : list) {
            observer.update(context);
        }
    }
}

// 三个观察者

// 秘书
public class Secretary implements Observer {
    // 观察领导要干什么
    public void update(String context) {
        System.out.println("领导要回家了,秘书和领导一起回家。。。");
    }
}

// 司机
public class Driver implements Observer {
    // 观察领导要干什么
    public void update(String context) {
        System.out.println("领导要回家了,司机将车从车库开出来!");
    }
}

// 清洁工
public class Cleaner implements Observer {
    // 观察领导要干什么
    public void update(String context) {
        System.out.println("领导要回家了,清洁工准备打扫办公室!");
    }
}

// 在一个场景中运行代码
public class Client {
    public static void main(String[] args) {
        // 定义三个观察者
        Observer secretary = new Secretary();
        Observer driver = new Driver();
        Observer cleaner = new Cleaner();

        // 定义出被观察者:领导
        Leader leader = new Leader();

        // 三个观察者开始观察老板
        leader.addObserver(secretary);
        leader.addObserver(driver);
        leader.addObserver(cleaner);

        // 领导要回家,观察者开始行动
        leader.goHome();
    }
}

// 结果如下:
领导要回家了!
领导要回家了,秘书和领导一起回家。。。
领导要回家了,司机将车从车库开出来!
领导要回家了,清洁工准备打扫办公室!
深入分析——Observer是什么?
Observer的定义

观察者模式也叫发布订阅模式,这是一个经常会被用到的设计模式

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

image

类图分析如下:

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

  • Observer观察者:观察Subject的行为,接收到消息后触发相应操作(update())

  • ConcreteSubject具体的被观察者:定义被观察者自己的业务逻辑,同时定义对那些对象进行通知

  • ConcreteObserver具体观察者:接收消息,做出响应,每个观察者有自己的响应逻辑

其通用代码如下:

// 被观察者
public abstract class Subject {
    // 定义一个观察者数组,所有的观察者都会被放到这个数组里
    private List<Observer> list = new ArrayList<>(16);
    
    // 增加一个观察者
    public void addObserver(Observer o) {
        this.list.add(o);
    }
    
    // 删除一个观察者
    public void deleteObserver(Observer o) {
        this.list.remove(o);
    }
    
    // 通知所有观察者
    public void notifyObservers(Observer o) {
        for(Observer o : list) {
            o.uodate
        }
    }
}

// 具体的被观察者
public class ConcreteSubject extends Subject {
    // 业务逻辑
    public void doSomething() {
        /**
        * 业务
        */
        // 通知观察者
        super.notifyObservers();
    }
}

// 观察者
public interface Observer {
    // 更新方法
    public void update();
}

//具体观察者
public class ConcreteObserver implements Observer {
    // 实现更新方法
    public void update() {
        // 处理
    }
}

// 场景类
public class Client {
    public static void main(String[] args) {
        // 创建一个被观察作者
        ConcreteSubject subject = new ConcreteSubject();
        // 定义一个观察者
        Observer o = new ConcreteObserver();
        // 观察者观察被观察者
        subject.addObserver(o);
        // 被观察者行动
        subject.doSomething();
    }
}
Observer的扩展

 前面已经说过,观察者模式已经被整合到了JDK中,开发者只有实现java.util.Observable和java.util.Observer接口就能使用这个设计模式,下面是设计类图:

image

 观察类图发现,与原来的设计相比,在被观察者java.util.Observable中,只有一个通知的方法,其他的方法都被剔除了,变得更加精简,下面来看看改动后的效果:

// 只给出改动部分代码,其他部分与上面相同

// 优化后的被观察者
public class Leader extends Observable implements ILeader {
    // 领导下命令
    public void order() {
        System.out.println("领导下命令了!");
        super.setChanged();
        // 通知所有观察者
        this.notifyObservers("领导下命令了!");
    }

    // 领导回家
    public void goHome() {
        System.out.println("领导要回家了!");
        super.setChanged();
        // 通知所有观察者
        this.notifyObservers("领导要回家了!");
    }
}

// 优化后的观察者
public class Secretary implements Observer {
    // 观察领导要干什么
    public void update(Observable o, Object obj) {
        System.out.println("领导要回家了,秘书和领导一起回家。。。");
    }
}

// 场景类
public class Client {
    public static void main(String[] args) {
        // 被观察者
        Leader leader = new Leader();
        // 观察者
        Observer secretary = new Secretary();
        // 观察者开始观察
        leader.addObserver(secretary);
        leader.goHome();
    }
}

// 结果如下:
领导要回家了!
领导要回家了,秘书和领导一起回家。。。
Observer的优点
  • 观察者和被观察者之间是抽象耦合:增加观察和被观察变得容易

  • 建立了一套触发机制:被观察者一个对象的改变会引起多个对象作出回应

Observer的缺点
  • 开发效率和运行效率问题:牵一发动全身,一个被观察者,多个观察者,开发调试会很困难
Observer的应用场景
  • 关联行为场景

  • 事件多级触发场景

  • 跨系统的消息交换场景

在项目中使用Observer
  • 观察者被观察者之间的消息沟通:在实际项目中,观察者的Update()方法接受两个参数,一个是被观察者,一个是DTO(数据传输对象:纯洁的JavaBean,由被观察者生成,由观察者消费)

  • 观察者响应方式:假如有一个观察者多个被观察者那如何考虑性能

    • 采用多线程技术,这就是异步架构

    • 采用缓存技术,这就是同步架构

参考

《设计模式之禅》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值