目录
  • 代码背景
  • 观察者模式
    • 介绍
    • 实现
      • 观察者(学生)
      • 通知者(老师)
      • Main方法
      • 观察者
      • 通知者
      •  事件
      • 事件处理
  •  委托 介绍
    •  总结

      代码背景

      一个班级,有两类学生,A类:不学习,玩,但是玩的东西不一样,有的是做游戏,有的是看电视

      B类:放哨的学生,专门看老师的动向,如果老师进班了就立即通知大家。

      如此就形成了一个需求,放哨的学生要通知所有玩的学生:老师来了,而不同的学生有不同的反应,有的马上把电视关闭,有的停止玩游戏。

      观察者模式

      介绍

      观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
      这个主题对象在状态发生变化时,会通知所有的观察者对象,使他们能够自动更新自己。

      主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

      何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

      如何解决:使用面向对象技术,可以将这种依赖关系弱化。

      关键代码:在抽象类里有一个 ArrayList 存放观察者们。

      实现

      深入理解Java中观察者模式与委托的对比

      观察者(学生)

      /**
       * 抽象的观察者
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/10 - 15:32
       */
      public interface Observer {
          public abstract void updateState();
      }
      /**
       * 具体的观察者
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/10 - 15:39
       */
      public class ConcreteObserver implements Observer{
          //观察者的姓名
          private String name;
          //观察者的状态
          private String observerState;
          //明确具体的通知者
          private ConcreteSubject subject;
         //get set方法省略
          public ConcreteObserver(String name, ConcreteSubject subject) {
              this.name = name;
              this.subject = subject;
          }
          @Override
          public void updateState() {
              observerState=subject.getSubjectState();
              System.out.println(name+"在打游戏");
              String str=String.format("观察者%s的:新状态是%s", name,observerState);
              System.out.println(str);
          }
      }
      /**
       * 具体的观察者
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/10 - 15:39
       */
      public class ConcreteObserver2 implements Observer{
          //观察者的姓名
          private String name;
          //观察者的状态
          private String observerState;
          //明确具体的通知者
          private ConcreteSubject subject;
         //get set方法省略
          public ConcreteObserver2(String name, ConcreteSubject subject) {
              this.name = name;
              this.subject = subject;
          }
          @Override
          public void updateState() {
              observerState=subject.getSubjectState();
              System.out.println(name+"在看电视");
              String str=String.format("观察者%s:新状态是%s", name,observerState);
              System.out.println(str);
          }
      }

      通知者(老师)

      /**
       * 抽象的通知者
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/10 - 15:30
       */
      public abstract class Subject {
          //管理观察者的集合
          private List<Observer> observers=new ArrayList<>();
          //增加观察者
          public void add(Observer observer){
              observers.add(observer);
          }
          //减少观察者
          public void detach(Observer observer){
              observers.remove(observer);
          }
          /**
           * 通知所有的观察者
           */
          public void notifyMsg(){
              for (Observer observer : observers) {
                  observer.updateState();
              }
          }
      }
      /**
       * 具体的通知者
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/10 - 15:38
       */
      public class ConcreteSubject extends Subject {
          //通知者的状态
          private String subjectState;
          //get set方法
          public String getSubjectState() {
              return subjectState;
          }
          public void setSubjectState(String subjectState) {
              this.subjectState = subjectState;
          }
      }

      Main方法

      /**
       * 控制台Main方法
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/10 - 15:48
       */
      public class MainTest {
          public static void main(String[] args) {
              //创建一个主题/通知者
              ConcreteSubject subject=new ConcreteSubject();
              //new出观察者(学生)
              ConcreteObserver studentZhang = new ConcreteObserver("小张", subject);
              ConcreteObserver studentLiu = new ConcreteObserver("小刘", subject);
              ConcreteObserver studentWang = new ConcreteObserver("小王", subject);
              //将观察者添加到通知队列里
              subject.add(studentZhang);
              subject.add(studentLiu);
              subject.add(studentWang);
              //通知者(老师)状态修改,通知每个学生
              subject.setSubjectState("老师回来了,我要好好学习");
              subject.notifyMsg();
              System.out.println("-----------");
          }
      }

      深入理解Java中观察者模式与委托的对比

       委托 介绍

      委托可以看做是函数的抽象,是函数的“类”。委托的实例将代表一个具体的函数
      一个委托可以搭载多个方法,所有的方法被依次唤起。可以使委托对象所搭载的方法并不需要属于同一类。
      委托事件模型可以由三个组件定义:事件、事件源和事件侦听器。

      委托的实现简单来讲就是用反射来实现的。

      实现

      深入理解Java中观察者模式与委托的对比

      观察者

      /**
       * 监听器/观察者 玩游戏
       * 事件监听器
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:17
       */
      public class PlayingGameListener {
          public PlayingGameListener(){
              System.out.println("我正在玩游戏 开始时间"+new Date());
          }
          public void stopPlayingGame(Date date){
              System.out.println("老师来了,快回到座位上,结束时间"+date);
          }
      }
      /**
       * 监听器/观察者 看电视
       * 事件监听器
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:17
       */
      public class WatchingTVListener {
          public WatchingTVListener(){
              System.out.println("我正在看电视 "+new Date());
          }
          public void stopWatchingTV(Date date){
              System.out.println("老师来了,快关闭电视 。 结束时间"+date);
          }
      }

      通知者

      /**
       * 通知者的抽象类
       * 事件源
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:15
       */
      public abstract class Notifier {
          //每个通知者都有一个需要通知的队列(通知:对象、方法、参数)
          private EventHandler eventHandler=new EventHandler();
          public EventHandler getEventHandler() {
              return eventHandler;
          }
          public void setEventHandler(EventHandler eventHandler) {
              this.eventHandler = eventHandler;
          }
          //增加需要帮忙放哨的学生
          public abstract void addListener(Object object,String methodName,Object...args);
          //告诉所有要帮忙放哨的学生:老师来了
          public abstract void notifyX();
      }
      /**
       * 通知者的子类,放哨人
       * 事件源
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:15
       */
      public class GoodNotifier extends Notifier {
          @Override
          public void addListener(Object object, String methodName, Object...args) {
              System.out.println("有新的同学委托尽职尽责的放哨人!");
              this.getEventHandler().addEvent(object, methodName, args);
          }
          @Override
          public void notifyX() {
              System.out.println("尽职尽责的放哨人告诉所有需要帮忙的同学:老师来了");
              try{
                  //优化:异步通知
                  this.getEventHandler().notifyX();
              }catch(Exception e){
                  e.printStackTrace();
              }
          }
      }

       事件

      /**
       * 抽象出的事件类,也可以称为方法类
       * 事件
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:03
       */
      public class Event {
          //要执行方法的对象
          private Object object;
          //要执行的方法名称
          private String methodName;
          //要执行方法的参数
          private Object[] params;
          //要执行方法的参数类型
          private Class[] paramTypes;
          //若干setter getter
          public Object getObject() {
              return object;
          }
          public String getMethodName() {
              return methodName;
          }
          public void setMethodName(String methodName) {
              this.methodName = methodName;
          }
          public Object[] getParams() {
              return params;
          }
          public void setParams(Object[] params) {
              this.params = params;
          }
          public Class[] getParamTypes() {
              return paramTypes;
          }
          public void setParamTypes(Class[] paramTypes) {
              this.paramTypes = paramTypes;
          }
          public Event(){
          }
          public Event(Object object,String methodName,Object...args){
              this.object=object;
              this.methodName=methodName;
              this.params=args;
              contractParamTypes(this.params);
          }
          //根据参数数组生成参数类型数组
          private void contractParamTypes(Object[] params){
              this.paramTypes=new Class[params.length];
              for(int i=0;i<params.length;i++){
                  this.paramTypes[i]=params[i].getClass();
              }
          }
          //执行该 对象的该方法
          public void invoke() throws Exception{
              //通过class,method,paramTypes 确定执行哪个类的哪个方法
              Method method=object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
              if(null==method){
                  return;
              }
              //方法执行
              method.invoke(this.getObject(), this.getParams());
          }
      }

      事件处理

      /**
       * 管理哪些事件需要执行
       * 管理事件
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:03
       */
      public class EventHandler {
          //是用一个List
          private List<Event> objects;
          //添加某个对象要执行的事件,及需要的参数
          public void addEvent(Object object,String methodName,Object...args){
              objects.add(new Event(object,methodName,args));
          }
          public EventHandler(){
              objects=new ArrayList<Event>();
          }
          //通知所有的对象执行指定的事件
          public void notifyX() throws Exception{
              for(Event e : objects){
                  e.invoke();
              }
          }
      }

      Main方法

      /**
       * 启动类
       *
       * @author Promsing(张有博)
       * @version 1.0.0
       * @since 2022/5/8 - 11:19
       */
      public class EventMain {
          public static void main(String[] args) {
              //创建一个尽职尽责的放哨者
              Notifier goodNotifier = new GoodNotifier();
              //创建一个玩游戏的同学,开始玩游戏
              PlayingGameListener playingGameListener = new PlayingGameListener();
              //创建一个看电视的同学,开始看电视
              WatchingTVListener watchingTVListener = new WatchingTVListener();
              //玩游戏的同学告诉放哨的同学,老师来了告诉一下
              goodNotifier.addListener(playingGameListener, "stopPlayingGame", new Date());
              //看电视的同学告诉放哨的同学,老师来了告诉一下
              goodNotifier.addListener(watchingTVListener, "stopWatchingTV", new Date());
              try {
                  //一点时间后
                  Thread.sleep(1000);
              } catch (Exception e) {
                  e.printStackTrace();
              }
              //老师出现,放哨的人通知所有要帮忙的同学:老师来了
              goodNotifier.notifyX();
          }
      }

      深入理解Java中观察者模式与委托的对比

       总结

      1.先有观察者模式后有委托事件技术
      2.观察者模式只能通知继承 Observer类 的子类,也可以将Observer改成接口

      for (Observer observer : observers) {
              observer.updateState();
      }

      3.委托可以通知任何类的任何方法。反射、everone

       Method method=object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
      if(null==method){
              return;
      }
       method.invoke(this.getObject(), this.getParams());

      4.委托与观察者比多了一个事件执行者,解除观察者与通知者的耦合,可以做到通知任何对象的任何方法。让A类学生和B类学生完全解耦,即A类完全不知道B类的学生,却可以通知B类的学生

      6.建立一套触发机制,可以使用异步通知

      7.观察者/委托挺像MQ里边的订阅发布。生产者、队列、消费者。

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。