范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

设计模式责任链模式

  行为型模式
  责任链模式 将多个对象连成一个链条,并沿着这条链传递请求,使得每个对象都有机会处理请求,直到有一个对象或者每个对象都能处理这个请求。 组成
  多个对象要能组成一个"链表"结构,每个对象应该继承自同一个类或实现同一个接口,并且每个对象要持有下一个对象的引用。因此,责任链的组成如下图所示:
  图1. 责任链模式的组成
  图中各个组成的作用: Handler:定义一个处理请求的接口,持有对自身的引用; ConcreteHandler:接口的具体实现,负责处理请求或转发请求,需要能判断"是否处理当前请求";
  从链中第一个对象开始,每个对象要么处理请求,要么转发给下一个对象。提交请求的对象(用户、客户端)并不知道哪一个对象会处理他的请求,只能保证他的请求一定会被处理(请求有一个 隐式的接收者 )。请求要能够沿着链条转发,并且保证接收者是隐式的,链上每个对象都要有一致的处理请求和转发给后一个对象的接口(有相同的对外方法)。 应用场景
  当存在以下情况时,使用责任链 模式: 有多个对象可以处理一个请求,哪个对象处理该请求在运行时自动确定; 想在不明确指定接受者的情况下,向多个对象中的一个提交一个请求; 可处理一个请求的对象集合 应该能够被动态指定 ; 示例代码 // Handler 接口  public interface Handler {      // 对后继者的引用      protected Handler next;            /**       * 处理方法       */      public void handle(Request request);  }    // 实现类A  public class HandlerA implements Handler {            @Override      public void handle(Request request) {          // TODO 实现自己的处理逻辑          // ....          // 指派给下一个          if(next != null) {              next.handle(request);          }      }  }    // 实现类B  public class HandlerB implements Handler {        @Override      public void handle(Request request) {          // TODO 实现自己的处理逻辑          // ....          // 指派给下一个          if(next != null) {              next.handle(request);          }      }  }    // 把 HandlerA 和 HandlerB 组成一个链条  HandlerA handlerA = new HandlerA();  HandlerB handlerB = new HandlerB();  handlerA.setNext(handlerB);过滤器
  "责任链模式"的一个经典示例是容器的过滤器。 FilterChain
  因为责任链中每个对象要能指向下一个对象,所以责任链的一个关键问题是:如何维护实现类之间的连接关系。上面的示例代码中,使用指向下一个对象的引用字段  next   来维护这种关系,过滤器使用一个对象 javax.servlet.FilterChain   来维护一个对象数组。 FilterChain   接口的 UML 如下图所示:
  图2. FilterChain 接口的实现关系
  FilterChain  代码如下:  public interface FilterChain {        public void doFilter(ServletRequest request, ServletResponse response)              throws IOException, ServletException;    }
  FilterChain 只提供了一个方法,请求参数是 "request、response",从前面对"责任链"的介绍可知,在该方法中既要要调用链中对象的过滤方法,还要能请求参数转发到链中的下一个对象。下面,通过它的实现类  ApplicationFilterChain   查看它的实现。 ApplicationFilterChain public final class ApplicationFilterChain implements FilterChain {      /**       * Filters 数组       */      private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];      /**       * Filters 数组处理请求的对象下标       */      private int pos = 0;      /**       * Filters 数组中对象的个数       */      private int n = 0;        // FilterChain Methods        @Override      public void doFilter(ServletRequest request, ServletResponse response)          throws IOException, ServletException {          // ...其他的省略,主要是调用了这个方法执行过滤....          internalDoFilter(req,res);      }            // 真正处理请求的方法      private void internalDoFilter(ServletRequest request, ServletResponse response)          throws IOException, ServletException {            // 如果当前下标 pos < n,就取出当前对象,执行对象的 doFilter() 方法          // 注意:pos++          if (pos < n) {              ApplicationFilterConfig filterConfig = filters[pos++];              try {                  Filter filter = filterConfig.getFilter();                  if( Globals.IS_SECURITY_ENABLED ) {                      // 省略...                  } else {                      // 执行过滤器方法                      filter.doFilter(request, response, this);                   }              } catch (IOException | ServletException | RuntimeException e) {                  throw e;              } catch (Throwable e) {                  e = ExceptionUtils.unwrapInvocationTargetException(e);                  ExceptionUtils.handleThrowable(e);                  throw new ServletException(sm.getString("filterChain.filter"), e);              }              return;          }      }        /**       * 把一个过滤器添加到 filters 数组中       */      void addFilter(ApplicationFilterConfig filterConfig) {          // Prevent the same filter being added multiple times          for(ApplicationFilterConfig filter:filters)              if(filter==filterConfig)                  return;            if (n == filters.length) {              ApplicationFilterConfig[] newFilters =                  new ApplicationFilterConfig[n + INCREMENT];              System.arraycopy(filters, 0, newFilters, 0, n);              filters = newFilters;          }          filters[n++] = filterConfig;      }  }
  从源码得到以下信息: 有一个  ApplicationFilterConfig   数组(对象数组),每个  ApplicationFilterConfig   对象持有一个  Filter   变量; 参数  pos   、  n   分别表示当前数组中正在使用的过滤器下标和数组的总长度,每执行一次方法,pos 值就会加1; 在启动时, addFilter()   方法把  ApplicationFilterConfig   对象添加到数组中,并且保证了不会重复添加; 在  internalDoFilter()   方法中,取出数组中  pos   下标处的  filterConfig   和  filter   ,然后执行 filter   对象  doFilter()   方法;
  在上面的代码中,并没有看到当前对象把请求转发给下一个对象(执行了 pos++,把数组下标加1),对象只执行了自身的 doFileter()   方法,很显然转发操作就发生在这个  Filter   对象的 doFileter()   方法中。 Filter
  Filter   接口的源码如下:  public interface Filter {           public default void init(FilterConfig filterConfig) throws ServletException {}      // 除了 FilterChain 中的两个参数,还传入了 FilterChain 对象      public void doFilter(ServletRequest request, ServletResponse response,              FilterChain chain) throws IOException, ServletException;        public default void destroy() {}  }
  doFilter()   方法中传入了3个参数:request、response、FilterChain。
  进入到最简单的  Filter   实现类  SessionInitializerFilter   中,该方法代码如下:  public class SessionInitializerFilter implements Filter {            @Override      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {          ((HttpServletRequest)request).getSession();          chain.doFilter(request, response);      }  }
  在  doFilter()   方法中,调用了 FilterChain.doFilter()   方法。从前面已知 FilterChain.doFilter()   方法会取出下标 pos 处的 Filter,而在调用当前 Filter 对象的  doFilter()   方法之前,应执行了  pos++   方法,把 pos 值加1,所以这里会取出数组中下一个 Filter,从而实现了请求转发。
  因此,每个 Filter  实现类在处理完自己的逻辑后,通过调用  FilterChain  的方法来把请求转发给下一个过滤器。整个过程和时序图如下图所示:
  图3.1 Filter的调用和转发过程
  图3.2. Filter的方法调用时序图
  前面展示了 指针、数组 形式的"责任链"实现方式,实际上"责任链"的实现方式是很多样的,需要根据业务需求选择一个合适的方式来实现,比如 Netty 的  ChannelPipeline   使用了一个双向链表实现了 ChannelHandler   的责任链。 优点和缺点请求的提交者(用户、客户端)并不知道最终是由哪个对象处理他的请求,只知道他的请求会被处理,这降低了请求与处理对象之间的耦合; 我们可以根据业务需要,动态地增加、删减责任链上的处理对象,而不会影响到已有的代码,增强了指派职责的灵活; 总结
  对同一个请求要连续做多种不同的处理时,可以使用责任链模式。
  和"策略模式"很相似,都能实现"请求与处理对象解耦",但"责任链模式"可以依次执行多个方法,"策略模式"是在多个方法中选择一个。 参考阅读
  1、Erich Gamma, Richard Helm, Ralph Johnson, Jojn Vlissides. 设计模式--可复用面向对象软件的基础[M]. 机械工业出版社,北京. 2018.11

国际足协女足世界杯已经卖出超过50万张门票,中国是重点购买者在这个阖家欢乐的时刻,首先祝所有的读者和球迷朋友们新年快乐,兔年大吉!精彩的卡塔尔世界杯转瞬即逝,短短一个月的时间却让许多球迷难以忘怀。而在今年的七月份,我们将会迎来女足世界杯。本这是脐疝吗?需要怎么护理呀?新生儿由于腹压比较高,在哭闹或者肚子胀气时,会引发脐疝。脐疝是指腹腔内容物由脐部薄弱区突出的腹外疝。脐位于腹壁正中部,在胚胎发育过程中,是腹壁最晚闭合的部位。脐部缺少脂肪组织,使腹更年期女性应该如何避孕?点击蓝字关注我们更年期女性应该如何避孕?更年期的女性卵巢功能开始下降,月经变得不规律,经量也明显稀少,但仍会有不规则的排卵。只要有成熟的卵泡排出,女性就有怀孕的可能。据世界卫生组织我在这里过大年五百岁的福山大集将成打卡地大小新闻1月20日讯(YMG全媒体记者邹春霞通讯员刘丽丽摄影报道)在福山大集里转一圈,身上一定沾满了年味儿。春节前夕,在中国许多地方都有赶大集备年货的传统。福山大集作为烟台古老的集812万盆鲜花装点最美回家路昆明欢迎你对于在外工作的云南人来说,回乡的第一站通常落地昆明。近日,昆明用鲜花常开不败的面貌迎接着归乡的云南人。1月19日,春城晚报开屏新闻记者从昆明市园林绿化局了解到,今年昆明市在春节氛围多彩石家庄非遗过大年丨年味儿里的石家庄传统美食过大年1月14日,由石家庄市文化广电和旅游局主办,河北新闻网承办,各县(市区)文化和旅游部门协办的玉兔迎春多彩石家庄非遗过大年系列活动正式开启!活动将陆续推出年味儿里的石家庄非遗展览,介创名县看今昭过年不打烊,嗨尽兴,就在昭化古城!新年倒计时打铁花1月22日1月27日(大年初一至初六)每晚945分网络图初一至初六连续六天在昭化古城太极广场上一起欣赏漫天星光场面震撼的传统民俗技艺打铁花!在绚烂的火花下许下对未来兔然来袭!福山区一大波文旅活动拉满过年氛围!倒计时春节假期即将到来激动的心颤抖的手小编已经迫不及待啦你是不是也做好过年的准备啦实不相瞒福山区文化和旅游局新春套餐已经准备好了初一到十五精彩不重样,兔您乐呵!2023NEWYEA重庆喊你来过年共享冰雪奇缘逍遥巫溪请你吃烤鱼岁末临近,新春将至你去哪里过年?快来巫溪吃地道的烤鱼耍刺激滑雪探古老盐文化这个春节逍遥巫溪邀你,同享冰雪奇缘!红池坝国家森林公园红池坝国家森林公园,海拔在1100米至2630米之间春节出游十大热门目的地之一的长沙给您准备了这份文旅盛宴菜单焰火点亮星城。除署名外均为资料图片炭河古城过大年活动。华谊兄弟(长沙)电影小镇一路好戏过大年主题活动将欢乐亮相。迎新春原创大展喜湘逢湖南吉祥艺术大观。长沙晚报全媒体记者邹麟摄长沙晚绵竹这个景区将开展游园活动,还有新年礼品拿哦兔年大吉新年伊始万象更新,新年的曙光已经扑面而来!为营造新年欢乐的氛围,丰富和活跃节日期间群众文化生活,让游客通过参与活动的形式感受到新年年味儿,绵竹市汉旺地震遗址公园特举办喜迎新
为何四川是中西部冰雪休闲带代表?揭秘冰雪热背后的气候密码热雪四川封面新闻记者吴冰清冬奥会赛场上,中国体育健儿不断刷新历史,闪闪发光的奥运记忆背后,成都屡屡被提及。文化和旅游部公布的10条全国冰雪旅游精品线路中,成都峨眉山等涵盖其中。2020年中小车床车房车分不清楚?这不是碰瓷么?有些瓜房车玩家不背一个好的旅游目的地,真正的房车用户会格外爱惜,因为我这趟走了,过一阵没准我还会来,好的旅居环境要保持,不能走了让人戳脊梁骨。但对于很多自驾游新手而言(这里不泛指房车床车甚至自驾游小重磅!加拿大官宣入境新规,核酸隔离政策大改,赴华航班再遭禁止,美国发旅游警告专家不能躺平下一个变种更厉害!刚刚!加拿大卫生部长JeanYvesDuclos宣布重磅入境新政,从2月28日开始,取消对完全接种的国际旅客72小时核酸检测证明要求,未接种疫苗的孩童一百个胡桃一起摇?事实证明中国玩家到底有多爱这个魔性少女桃一百个胡桃一起摇?用事实证明中国玩家到底有多爱这个魔性少女桃你见过。一百个胡桃一起摇嘛?胡桃,游戏原神中的5星火系角色。一百个胡桃一起摇讲的是在漫展中,众多美少女COSER,意外的冬奥冠军苏翊鸣也是西藏旅游粉丝!跟着他打卡同款旅游目的地吧!昨天,在北京冬奥会单板滑雪男子大跳台决赛中苏翊鸣以182。50分夺冠这是在本届冬奥会上中国代表团获得的第6枚金牌也是苏翊鸣个人收获的第2枚奖牌来源人民体育祝贺苏翊鸣!小编惊喜地在苏单局限时赛中国只剩一人,梁文博独闯32强!丁俊晖核酸检测阴性1月22日,2022年世界斯诺克单局限时赛展开第三轮的角逐,八位出战的中国军团成员,表现不佳,最终只有梁文博一人赢球晋级,独闯32强,第三轮将对阵英格兰亚裔选手林彬峰。另外世界排名iPhone突然掉电快是什么情况,该如何解决?如果您的iPhone在使用过程中,出现掉电很快甚至突然关机的情况,您可以参考以下原因及解决办法1。电池本身的老化如果你的iPhone已经使用一年半以上的时间,电池的寿命肯定会有损耗孩子开学了,轮着做这6道菜,荤素搭配营养足,为春天长身体助力元宵节过完了,年也过完了,孩子也开学了,春天也到了。春天,万物竞相生长,孩子也到了一年中快速发育长个的时候,孩子的生长发育需要丰富的蛋白质,维生素以及钙质等等微量元素,家长要利用生常把这几句口头禅挂在嘴边的孩子,往往情商低,希望你家娃没说过孩子在日常的生活中,免不了会逐渐地形成一些口头禅,这原本无可厚非,但如果孩子的情商较低,那么形成的口头禅就可能让人不适。小旭是一名五年级的小学生,而他就有一句口头禅是关我啥事?无论新春云游记川西,是我魂牵梦萦的远方,是跳跃于我心中不曾止息的诗行。十余年来,为踏上那一方秘境,我一次又一次畅想谋划,却一次又一次叹息失望,深切地体会到了公务在身,身不由己的无奈。一次偶然相约生活在北京,却遇见另一个江南春节前夕,一家人自驾游去了古北水镇。慢游小镇拱桥石板路山水园林,这里既有江南小桥流水人家的灵秀温婉,又有古道西风瘦马的北国之风。这是北京吗?怎么恍惚在乌镇!是的,这就是北京的水乡古