“数据结构” 模式
- 常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用。这时候,将这些特定的数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。
- 典型模式
- Composite
- Iterator
- Chain of Resposibility
一、场景分析
假设我们要实现一个请假或加薪的申请系统,请假时,如果天数不超过两天,只需要项目经理批准,如果大于2天且不超过5天,就需要总监批准,如果大于5天,就要总经理批准;申请加薪,都需要总经理进行批准。
要实现这个,我们可以首先把申请抽象出一个类
//请求
class Request {
//申请类别
public String requestType;
//申请内容
public String requestContent;
//数量
public int number;
}
然后再写一个管理者类,管理者负责审批
//管理者
class Manager {
protect String name;
public Manager(String name) {
this.name = name;
}
public void getResult(String managerLevel, Request request) {
if(managerLevel == "经理") {
if(request.requestType == "请假" && request.number <= 2) {
System.out.println("请假小于2,被批准");
} else {
System.out.println("我无权处理");
}
}
else if(managerLevle == "总监") {
if(reuqest.requestType == "请假" && request.number <= 5) {
System.out.println("请假小于5,被批准");
} else {
System.out.println("我无权处理");
}
}
else if(managerLevel == "总经理") {
if(request.requestType == "请假") {
System.out.println("批准");
} else if(request.requestType == "加薪" && request.number <= 500) {
System.out.println("批准");
} else if(request.requestType == "加薪" && request.number > 500) {
System.out.println("再说吧");
}
}
}
}
上面的这段代码中,getResult方法太长,充斥着“坏代码”的味道,有以下几点:
-
员工在提交申请时,必须要知道该申请对应的是哪个级别的管理者;
-
如果以后需要添加管理类别,如部门经理、人力总监、副总经理等,那就意味着都要去改变这个类,违反了开放-封闭原则
在这里,管理者类别是变化点,我们可以把它抽象出通用的管理者类,利用多态来化解分支带来的僵化;对于实现经理无权时上报总监,总监无权时在上报总经理这样的功能,我们可以把用户的请求传递,知道解决这个请求为止。
这就是职责链模式的意图了。
用职责链模式重构上述的代码
class Manager {
public Manager superior;
public void setSuppior(Manager superior) {
this.superior = superior;
}
pulbic abstract void processRequest(Request request;);
}
class JingLi extends Manager {
public JingLi(String name) {
super(name);
}
@Override
public void processRequest(Request request) {
System.out.printf("请求是%s%d, ", request.requestType, request.number);
if(request.requestType.equals("请假") && request.number <= 2) {
System.out.println("被经理批准");
} else {
System.out.println("经理无权处理");
superior.processRequest(request);
}
}
}
class ZongJian extends Manager {
public ZongJian(String name) {
super(name);
}
@Override
public void processRequest(Request request) {
System.out.printf("请求是%s%d, ", request.requestType, request.number);
if(request.requestType.equals("请假") && request.number <= 5) {
System.out.println("被总监批准");
} else {
System.out.println("总监无权处理");
superior.processRequest(request);
}
}
}
客户端的代码如下:
public class ChainOfResponsibility {
public static void main(String[] args) {
//定义好组织架构,完全可以根据实际需求来更改设置
JingLi jingli = new JingLi("经理");
ZongJian zongjian = new ZongJian("总监");
ZongJingLi zongjingli = new ZongJingLi("总经理");
jingli.setSuperior(zongjian);
zongjian.setSuperior(zongjingli);
//客户端的所有申请都是由 "经理" 发起的,但实际谁来决策由具体管理者来处理,客户端并不知道
Request request1 = new Request();
request1.requestType = "请假";
request1.requestContent = "小菜请假";
request1.number = 1;
jingli.processRequest(request1);
Request request2 = new Request();
request2.requestType = "请假";
request2.requestContent = "小菜请假";
request2.number = 3;
jingli.processRequest(request2);
Request request3 = new Request();
request3.requestType = "加薪";
request3.requestContent = "小菜请求加薪";
request3.number = 500;
jingli.processRequest(request3);
}
}
数出结果是:
请求是请假1, 被经理批准
请求是请假3, 经理无权处理
请求是请假3, 被总监批准
请求是加薪500, 经理无权处理
请求是加薪500, 总监无权处理
请求是加薪500, 总经理批准
通过这种方式,很好地解决了原来大量分支判断造成难维护、灵活性差的问题。
二、动机
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
三、定义
类图:
参与者:
- Handler(如Manager):
- 定义一个处理请求的接口
- 实现后继链
- ConcreteHandler(如JingLi、ZongJingLi):
- 处理它所负责的请求
- 如果可处理该请求,就处理之;否则转发给它的后继者
- Client
- 向链上的具体处理者对象提交请求
使用场景:
- 有多个对象可以处理同一个请求,哪个对象处理该请求在运行时刻自动确定
- 你想在不明确接受者的情况下,想多个对象中的一个提交一个请求
- 可处理一个请求的对象集合应该被动态指定