使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
案例1:
1.需要对一个消息符号,表情,标签处理,有敏感字就不往下执行了,返回已经处理的消息。
package com.zcm.cor;
import lombok.*;
import org.bouncycastle.i18n.filter.*;
import java.util.*;
/**
* @program: demo
* @ClassName:Msg
* @Description:
* @Author:zcm
* @Date:2021/2/2 15:44
*/
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("v,v,v 0_0 欢迎大家访问 <baidu.com> 我们都是文明的China人哦,我们都996,699");
//链条块1
FilterChain fc1 = new FilterChain();
fc1.add(new HtmlFilter()).add(new SensitiveFilter());
//链条块2
FilterChain fc2 = new FilterChain();
fc2.add(new FaceFilter()).add(new UrlFilter());
//将链条块1和链条块2连在一起,形成一条链
fc1.add(fc2);
//开始对文本处理
fc1.doFilter(msg);
System.out.println("原文:" + msg);
System.out.println();
System.out.println("处理后:" + msg.getMsg());
}
}
@Data
class Msg {
private String name;
private String msg;
}
interface Filter {
Boolean doFilter(Msg msg);
}
/**
* @Description:替换html尖括号文本
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:31
*/
class HtmlFilter implements Filter {
@Override
public Boolean doFilter(Msg msg) {
String r = msg.getMsg().replace("<", "[").replace(">", "]");
msg.setMsg(r);
return true;
}
}
/**
* @Description:替换地址
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:31
*/
class UrlFilter implements Filter {
@Override
public Boolean doFilter(Msg msg) {
String r = msg.getMsg().replace("baidu.com", "taobao.com");
msg.setMsg(r);
return true;
}
}
/**
* @Description:替换敏感数字
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:31
*/
class SensitiveFilter implements Filter {
@Override
public Boolean doFilter(Msg msg) {
String r = msg.getMsg().replace("996", "955");
msg.setMsg(r);
return false;
}
}
/**
* @Description:将符号替换成表情
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:32
*/
class FaceFilter implements Filter {
@Override
public Boolean doFilter(Msg msg) {
String r = msg.getMsg().replace("v", "QAQ").replace("0_0", "33");
msg.setMsg(r);
return true;
}
}
/**
* @Description:过滤器
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:32
*/
class FilterChain implements Filter {
public List<Filter> filters = new ArrayList<>();
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
@Override
public Boolean doFilter(Msg msg) {
for (Filter filter : filters) {
//如果链条上的一环,有敏感词的 返回失败
if (!filter.doFilter(msg)) {
return false;
}
}
return true;
}
}
2.效果图:案例一主要就是针对消息的一下特殊处理
3.流程图
4.类图
案例2:
对文字处理
package com.zcm.cor.servlet;
import lombok.*;
import java.util.*;
/**
* @program: demo
* @ClassName:ServletMain
* @Description:
* @Author:zcm
* @Date:2021/2/3 14:26
*/
public class ServletMain {
public static void main(String[] args) {
FilterChain chain = new FilterChain();
Request request = new Request();
request.setMsg("你好呀,<baidui.com>,感谢遇见!");
Response response = new Response();
chain.add(new HtmlFilter()).add(new UrlFilter());
chain.doFilter(request, response, chain);
System.out.println("请求原文:" + request.getMsg());
System.out.println("响应消息:" + response.getMsg());
}
}
@Data
class Request {
private String name;
private String msg;
}
@Data
class Response {
private String name;
private String msg;
}
interface Filter {
Boolean doFilter(Request request, Response response, FilterChain chain);
}
/**
* @Description:替换html尖括号文本
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:31
*/
class HtmlFilter implements Filter {
@Override
public Boolean doFilter(Request request, Response response, FilterChain chain) {
String r = request.getMsg().replace("<", "[").replace(">", "]");
request.setMsg(r);
StringBuilder builder = new StringBuilder();
builder.append("-html:").append(r);
response.setMsg(builder.toString());
chain.doFilter(request, response, chain);
return true;
}
}
/**
* @Description:替换地址
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:31
*/
class UrlFilter implements Filter {
@Override
public Boolean doFilter(Request request, Response response, FilterChain chain) {
String r = request.getMsg().replace(".com", ".net");
request.setMsg(r);
StringBuilder builder = new StringBuilder();
String s1 = response.getMsg().replaceAll("感谢遇见!", "感谢思念");
String msg = builder.append(s1).append("-url:").toString();
String s = msg.replaceAll(request.getMsg(), r);
response.setMsg(s);
chain.doFilter(request, response, chain);
return true;
}
}
/**
* @Description:过滤器
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/2 16:32
*/
class FilterChain implements Filter {
public List<Filter> filters = new ArrayList<>();
int index = 0;
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
@Override
public Boolean doFilter(Request request, Response response, FilterChain chain) {
if (index == filters.size()) {
return false;
}
//如果链条上的一环,有敏感词的
Filter filter = filters.get(index);
index++;
return filter.doFilter(request, response, chain);
}
}
2.效果图 :案例二和案例一的区别请求和响应对象独立的
案例3:模拟客户端请求服务端的过滤器,有点类似Javax.servlet.Filter
1.客户端发送登录请求
2.服务端接收到客户端的请求
3.开始检验客户端的登录请求参数是否正确?
4.服务端校验客户端携带的登录参数异常,开始对客户端做出相对应的响应。
5.客户端接到服务端对自己的回应。
模拟用户登录场景
package com.zcm.cor.servlet.login;
import com.alibaba.fastjson.*;
import lombok.*;
import org.springframework.util.*;
import java.util.*;
/**
* @program: demo
* @ClassName:LoginMain
* @Description:
* @Author:zcm
* @Date:2021/2/3 18:00
*/
public class LoginMain {
public static void main(String[] args) {
FilterChain chain = new FilterChain()
.add(new CheckFilter())
.add(new BlacklistFilter());
HttpRequest request = new HttpRequest();
User user = new User();
user.setUserName("123456");
user.setPassword("1234156");
request.setToken(JSON.toJSONString(user));
HttpResponse response = new HttpResponse();
chain.doFilter(request, response, chain);
System.out.println(response.getCode());
System.out.println(response.getMsg());
}
}
@Data
class User {
private String userName;
private String password;
}
@Data
class HttpRequest {
private String token;
}
@Data
class HttpResponse {
private String msg;
private int code;
}
interface Filter {
Boolean doFilter(HttpRequest request, HttpResponse response, FilterChain chain);
}
/**
* @Description:参数检验 1.token携带的参数不可为空
* 2.账号和密码不可为空
* 3.账号密码是否正确
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 9:50
*/
class CheckFilter implements Filter {
@Override
public Boolean doFilter(HttpRequest request, HttpResponse response, FilterChain chain) {
if (StringUtils.isEmpty(request.getToken())) {
response.setCode(500);
response.setMsg("token令牌不可为空");
return false;
}
JSONObject jsonObject = JSONObject.parseObject(request.getToken());
String userName = jsonObject.getString("userName");
String password = jsonObject.getString("password");
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)) {
response.setCode(500);
response.setMsg("用户名或密码不能为空");
return false;
}
chain.doFilter(request, response, chain);
return true;
}
}
/**
* @Description:黑名单检验 4.该账号是否在黑名单
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 9:54
*/
class BlacklistFilter implements Filter {
@Override
public Boolean doFilter(HttpRequest request, HttpResponse response, FilterChain chain) {
String token = request.getToken();
JSONObject jsonObject = JSONObject.parseObject(token);
String userName = jsonObject.getString("userName");
if (!userName.equals("admin") && !password.equals("123456")) {
response.setCode(500);
response.setMsg("用户名或密码错误");
return false;
}
if (userName.equals("admin")) {
response.setCode(500);
response.setMsg("此账号被人举报,咱不能登录,请联系客服解封......");
return false;
}
System.out.println("登录成功");
chain.doFilter(request, response, chain);
return true;
}
}
class FilterChain implements Filter {
public List<Filter> filters = new ArrayList<>();
int index = 0;
public FilterChain add(Filter filter) {
filters.add(filter);
return this;
}
@Override
public Boolean doFilter(HttpRequest request, HttpResponse response, FilterChain chain) {
if (index == filters.size()) {
return false;
}
//如果链条上的一环,有敏感词的
Filter filter = filters.get(index);
index++;
return filter.doFilter(request, response, chain);
}
}
案例4【来自设计模式之禅】:
中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”,也就是说一个女性,在没有结婚的时候要听从于父亲,结了婚后听从于丈夫,丈夫死了还要听儿子的,举个例子来说,一个女的要出去逛街,同样这样的一个请求,在她没有出嫁前她必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?一般都是男的比女的死的早,还要问问儿子是否允许自己出去逛街,估计你下边马上要问要是没有儿子怎么办?请示小叔子、侄子等等,在父系社会中,妇女只占从属地位,现在想想中国的妇女还是比较悲惨的,逛个街还要请示来请示去,而且作为父亲、丈夫、儿子只有两种选择:要不承担起责任来告诉她允许或不允许逛街,要不就让她请示下一个人,这是整个社会体系的约束。
传统写法:
package com.zcm.cor.servlet.advance.tc;
import cn.hutool.core.util.*;
import java.util.*;
/**
* @program: demo
* @ClassName:TraditionalClient
* @Description:
* @Author:zcm
* @Date:2021/2/4 16:44
*/
public class TraditionalClient {
public static void main(String[] args) {
List<IWomen> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new Women(RandomUtil.randomInt(1,4), "我要去逛街~"));
}
IHandler fatherHandler = new FatherHandler();
IHandler husbandHandler = new HusbandHandler();
IHandler sonHandler = new SonHandler();
for (IWomen iWomen : list) {
switch (iWomen.getType()) {
case 1:
fatherHandler.getResponse(iWomen);
break;
case 2:
husbandHandler.getResponse(iWomen);
break;
case 3:
sonHandler.getResponse(iWomen);
break;
}
}
}
}
/**
* @program: demo
* @ClassName:Handler
* @Description:
* @Author:zcm
* @Date:2021/2/4 10:54
*/
interface IHandler {
/**
* @Description:做出响应
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:05
*/
void getResponse(IWomen women);
}
/**
* @Description:女人
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 10:58
*/
interface IWomen {
/**
* @Description:类型 1.未婚 2.结婚 3.守寡
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 10:57
*/
public int getType();
/**
* @Description:请求
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 10:57
*/
public String getRequest();
}
class Women implements IWomen {
//默认:未婚
private int type = 1;
//请求信息
private String request;
@Override
public int getType() {
return this.type;
}
@Override
public String getRequest() {
return this.request;
}
public Women(int type, String request) {
this.type = type;
switch (this.type) {
case 1:
this.request = "女儿的请求:" + request;
break;
case 1:
this.request = "妻子的请求:" + request;
break;
case 2:
this.request = "母亲的请求:" + request;
break;
}
}
}
/**
* @Description:向父亲请示
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:18
*/
class FatherHandler implements IHandler {
@Override
public void getResponse(IWomen women) {
System.out.println("----------------向父亲请示-----------------------");
System.out.println(women.getRequest());
System.out.println("父亲回答:同意");
}
}
/**
* @Description:向丈夫请示
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:18
*/
class HusbandHandler implements IHandler {
@Override
public void getResponse(IWomen women) {
System.out.println("----------------向丈夫请示-----------------------");
System.out.println(women.getRequest());
System.out.println("丈夫回答:不同意");
}
}
/**
* @Description:向儿子请示
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:18
*/
class SonHandler implements IHandler {
@Override
public void getResponse(IWomen women) {
System.out.println("----------------向儿子请示-----------------------");
System.out.println(women.getRequest());
System.out.println("儿子回答:同意");
}
}
耦合过重,违反了迪米特原则,异常情况没考虑,失去了面向对象的意义。既然有这么多的问题,那我们要想办法来解决这些问题,我们可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就回应处理,如果女儿已经出嫁了,那就要把这个请求转发到女婿来处理,那女婿一旦去了,那就由儿子来处理这个请求。
父亲、丈夫、儿子每个节点有两个选择:要么做出回应;要么把请求转发到后序环节。
责任链的写法
package com.zcm.cor.servlet.advance;
import java.util.*;
/**
* @program: demo
* @ClassName:Main
* @Description:
* @Author:zcm
* @Date:2021/2/4 11:27
*/
public class Main {
public static void main(String[] args) {
List<IWomen> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new Women(new Random().nextInt(3), "我要去逛街~"));
}
IHandler fatherHandler = new FatherHandler();
IHandler husbandHandler = new HusbandHandler();
IHandler sonHandler = new SonHandler();
fatherHandler.setNext(husbandHandler);
husbandHandler.setNext(sonHandler);
for (IWomen iWomen : list) {
fatherHandler.handlerMessage(iWomen);
}
}
}
/**
* @program: demo
* @ClassName:Handler
* @Description:
* @Author:zcm
* @Date:2021/2/4 10:54
*/
abstract class IHandler {
private int level = 0;
private IHandler nextHandler;
public IHandler(int level) {
this.level = level;
}
/**
* @Description:做出响应
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:05
*/
abstract void getResponse(IWomen women);
final void handlerMessage(IWomen women) {
if (women.getType() == this.level) {
this.getResponse(women);
} else {
if (this.nextHandler != null) { //有后续环节,才把请求往后递送
this.nextHandler.handlerMessage(women);
} else { //已经没有后续处理人了,不用处理了
System.out.println("-----------没地方请示了,不做处理!---------\n");
}
}
}
/* * 如果你属于你处理的返回,你应该让她找下一个环节的人,比如 * 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示 */
public void setNext(IHandler _handler) {
this.nextHandler = _handler;
}
}
/**
* @Description:女人
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 10:58
*/
interface IWomen {
/**
* @Description:类型 1.未婚 2.结婚 3.守寡
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 10:57
*/
public int getType();
/**
* @Description:请求
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 10:57
*/
public String getRequest();
}
class Women implements IWomen {
//默认:未婚
private int type = 1;
//请求信息
private String request;
@Override
public int getType() {
return this.type;
}
@Override
public String getRequest() {
return this.request;
}
public Women(int type, String request) {
this.type = type;
switch (this.type) {
case 0:
this.request = "女儿的请求:" + request;
break;
case 1:
this.request = "妻子的请求:" + request;
break;
case 2:
this.request = "母亲的请求:" + request;
break;
}
}
}
/**
* @Description:向父亲请示
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:18
*/
class FatherHandler extends IHandler {
public FatherHandler() {
super(0);
}
@Override
public void getResponse(IWomen women) {
System.out.println("----------------向父亲请示-----------------------");
System.out.println(women.getRequest());
System.out.println("父亲回答:同意");
}
}
/**
* @Description:向丈夫请示
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:18
*/
class HusbandHandler extends IHandler {
public HusbandHandler() {
super(1);
}
@Override
public void getResponse(IWomen women) {
System.out.println("----------------向丈夫请示-----------------------");
System.out.println(women.getRequest());
System.out.println("丈夫回答:不同意");
}
}
/**
* @Description:向儿子请示
* @Author: zcm
* @Version:v.2.7.1
* @Date:2021/2/4 11:18
*/
class SonHandler extends IHandler {
//儿子只处理母亲的请求
public SonHandler() {
super(2);
}
@Override
public void getResponse(IWomen women) {
System.out.println("----------------向儿子请示-----------------------");
System.out.println(women.getRequest());
System.out.println("儿子回答:同意");
}
}
总结:
优点:
1、降低代码耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点:
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。