二十:职责链模式详解(类似于spring的hangler处理请求)
定义:为了避免请求的发送者和接收者之间的耦合关系,使多个接受对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
“看这个定义,就是将一堆可以处理请求的对象连成一条链,然后一个一个试着处理请求。这好像是可以解决麦当劳订餐的问题的,我先来看看我刚才苦B的订餐过程是什么样子的。” “首先应该有一个麦当劳的分店的类,它的主要功能是可以订餐。”
“先来看看职责链模式的类图,这样比较好设计。”
“类图还是比较简单的啊,有一个通用的接口,然后就是若干个具体的处理者。按照现在麦当劳的情况来说,接口里handleRequest方法其实就是order(订餐)方法了,而setSuccessor方法,则是用来设置职责链的下一个处理者。”
“对于麦当劳的问题来说,每一个分店就是具体的处理者了,主要的改动应该是抽象出来一个接口以及职责链的连接过程,而刚才发送订单的时候是拆分成方法参数传递给订餐方法的,现在最好是把订单做成一个数据类。”
package com.chain; import java.util.Map; //订单类(相当于request,其实就是封装一个请求)
public class Order { private int x;
private int y;
private Map<String, Integer> order; public Order(int x, int y, Map<String, Integer> order) {
super();
this.x = x;
this.y = y;
this.order = order;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
} public Map<String, Integer> getOrder() {
return order;
} public void setOrder(Map<String, Integer> order) {
this.order = order;
} }
“下面便应该是分店接口了,它有两个方法,和类图当中的方法类似,只是名称略有改变。”
package com.chain;
//分店接口(相当于Hanlder)
public interface Subbranch { void setSuccessor(Subbranch subbranch); boolean handleOrder(Order order); }
“下面便是麦当劳分店的实现类了,它主要的改变是添加了一个属性(下一个分店),这应该就是链形成的基石了。”
package com.chain; import java.util.Collections;
import java.util.Map; //麦当劳分店
public class McSubbranch implements Subbranch{ private final static int MIN_DISTANCE = 500;//假设是500米以内送餐 private static int count;//类计数 private final int number;//分店号 private int x;//分店的横坐标,用于判断距离 private int y;//分店的纵坐标,用于判断距离 private Map<String, Integer> menu;//菜单 private Subbranch nextSubbranch;//下一家分店 public McSubbranch(int x, int y, Map<String, Integer> menu) {
super();
this.x = x;
this.y = y;
this.menu = menu;
number = ++count;
}
//设置下一家分店
public void setSuccessor(Subbranch subbranch) {
this.nextSubbranch = subbranch;
}
//按照职责链处理订单
public boolean handleOrder(Order order){
//如果距离小于500米并且订单中的食物不缺货,则订单成功,否则失败
if (CommonUtils.getDistance(order.getX(), order.getY(), this.x, this.y) < MIN_DISTANCE && !CommonUtils.outOfStock(menu, order.getOrder())) {
for (String name : order.getOrder().keySet()) {
menu.put(name, menu.get(name) - order.getOrder().get(name));
}
System.out.println("订餐成功,接受订单的分店是:" + this);
return true;
}
if (nextSubbranch == null) {
return false;
}
return nextSubbranch.handleOrder(order);
} public Map<String, Integer> getMenu() {
return Collections.unmodifiableMap(menu);
} public Subbranch getNextSubbranch() {
return nextSubbranch;
} public String toString() {
return "麦当劳分店第" + number + "个";
} }
“handleOrder方法中的逻辑就是职责链的精髓了,它会试图处理请求,如果处理不了,则交给链中的下一个分店。刚才用的CommonUtils应该不用变了。下面就看下有了职责链模式之后,我的订餐方式吧。”
package com.chain; import java.util.HashMap;
import java.util.Map; public class Client { public static void main(String[] args) {
//假设初始菜单都是以下这些东西
Map<String, Integer> menu = new HashMap<String, Integer>();
menu.put("汉堡", 5);
menu.put("薯条", 5);
menu.put("可乐", 5);
menu.put("雪碧", 5);
//假设有5个分店
Subbranch mcSubbranch1 = new McSubbranch(0, 0, new HashMap<String, Integer>(menu));
Subbranch mcSubbranch2 = new McSubbranch(100, 120, new HashMap<String, Integer>(menu));
Subbranch mcSubbranch3 = new McSubbranch(-100, -120, new HashMap<String, Integer>(menu));
Subbranch mcSubbranch4 = new McSubbranch(1000, 20, new HashMap<String, Integer>(menu));
Subbranch mcSubbranch5 = new McSubbranch(-500, 0, new HashMap<String, Integer>(menu)); //以下设置职责链
mcSubbranch4.setSuccessor(mcSubbranch5);
mcSubbranch3.setSuccessor(mcSubbranch4);
mcSubbranch2.setSuccessor(mcSubbranch3);
mcSubbranch1.setSuccessor(mcSubbranch2);
//小左开始订餐,假设小左的坐标是900,20
Map<String, Integer> order = new HashMap<String, Integer>();
order.put("汉堡", 2);
order.put("可乐", 1);
order.put("薯条", 1); print(mcSubbranch1);
System.out.println("------------------------------------------"); //小左开始订餐,直接找mcSubbranch1的这一家分店订餐即可
mcSubbranch1.handleOrder(new Order(900, 20, order)); System.out.println("------------------------------------------");
print(mcSubbranch1);
} public static void print(Subbranch subbranch){
if (subbranch == null ) {
return;
}
do {
if (subbranch instanceof McSubbranch) {
System.out.println("[" + subbranch + "]的菜单:" + ((McSubbranch) subbranch).getMenu());
}
} while ((subbranch = ((McSubbranch) subbranch).getNextSubbranch()) != null);
} }
“输出结果和刚才是一样的,不过这下我订餐就好办多了,直接找第一家分店订餐就行,至于到最后谁给我送餐,我就不用管了。”
1、客户端与具体的处理者解耦,客户端只认识一个Hanlder接口,降低了客户端(即请求发送者)与处理者的耦合度。
2、客户端和处理者都不关心职责链的具体结构,而是交给职责链的创造者(在上述例子当中则是交给了OrderManager),也正因为如此,当在职责链中添加处理者的时候,这对客户端和处理者来说,都是透明的,二者不知道也不必要知道职责链的变化。
二十:职责链模式详解(类似于spring的hangler处理请求)的更多相关文章
- C#设计模式之二十职责链模式(Chain of Responsibility Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中的例子吧,理解起来可能更 ...
- C#设计模式之二十一职责链模式(Chain of Responsibility Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中 ...
- (二十一)状态模式详解(DOTA版)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本次LZ给各位介绍状态模式, ...
- (二十三)原型模式详解(clone方法源码的简单剖析)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...
- 二十三:原型模式详解(clone复制方法源码)
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 定义比较简单,总结一下是通过实例指定种类,通过拷贝创建对象. 在JAVA语言中使用原型模式是非常 ...
- 夯实Java基础(二十五)——JDBC使用详解
1.JDBC介绍 JDBC的全称是Java Data Base Connectivity(Java数据库连接).是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问(例如MyS ...
- 设计模式(二十四)——职责链模式(SpringMVC源码分析)
1 学校 OA 系统的采购审批项目:需求是 采购员采购教学器材 1) 如果金额 小于等于 5000, 由教学主任审批 (0<=x<=5000) 2) 如果金额 小于等于 10000, ...
- Solr系列二:solr-部署详解(solr两种部署模式介绍、独立服务器模式详解、SolrCloud分布式集群模式详解)
一.solr两种部署模式介绍 Standalone Server 独立服务器模式:适用于数据规模不大的场景 SolrCloud 分布式集群模式:适用于数据规模大,高可靠.高可用.高并发的场景 二.独 ...
- C#设计模式——职责链模式(Chain Of Responsibility Pattern)
一.概述 在软件开发中,某一个对象的请求可能会被多个对象处理,但每次最多只有一个对象处理该请求,对这类问题如果显示指定请求的处理对象,那么势必会造成请求与处理的紧耦合,为了将请求与处理解耦,我们可以使 ...
随机推荐
- ...mapMutations前面的三个点什么意思
...mapMutations(['login']),对象展开运算符
- Mac进行Flutter开发的配置
可以参数Flutter中文网提供的方法: https://flutterchina.club/setup-macos/ 使用镜像 由于国内访问Flutter有时会受到限制(博主公司网络自带VPN没有这 ...
- 01 less的使用
使用less 安装两个包 1===>cnpm install less less-loader --save-dev less中的注释 以 //开头的注释 不会被编译到css文件中去 以 /** ...
- c# WF 第6节 MDI窗体
本节内容: 1:SDI 窗体是什么 2: MDI 窗体是什么 3:如何创建MDI窗体 1:SDI 窗体是什么 SDI 窗体 : single-document interface 单一的窗体:上篇的启 ...
- tomcat快速入门
简介 Tomcat 是什么 Tomcat 是由 Apache 开发的一个 Servlet 容器,实现了对 Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理 ...
- IntelliJ IDEA常用配置(三)
提示:对于一些通用的设置可以配置成全局的. 1. 主题配置 File - Settings - Color Scheme,默认的是Default(一个白色主题),Darcula是一个黑色主题. 我们也 ...
- NOIP模拟赛 最佳组合
题目描述 Description \(Bzeroth\) 大陆最终还是覆灭了,所以你需要为地灾军团服务了. 地灾军团军师黑袍不擅长写题面,所以你只需要看简化版的题意即可. 给定 \(3\) 个长度均为 ...
- Vue 使用comouted计算属性
computed计算属性 使用方法见代码: <!doctype html> <html lang="en"> <head> <meta c ...
- 用Python爬取猫眼上的top100评分电影
代码如下: # 注意encoding = 'utf-8'和ensure_ascii = False,不写的话不能输出汉字 import requests from requests.exception ...
- js/java 获取、添加、修改、删除cookie(最全)
一.cookie介绍 1.cookie的本来面目 HTTP协议本身是无状态的.什么是无状态呢,即服务器无法判断用户身份.Cookie实际上是一小段的文本信息(key-value格式).客户端向服务 ...