什么是行为型设计模式
行为型设计模式是对在不同的对象之间的责任划分和算法的抽象化。它不仅关注类和对象的结构,而且重点关注他们之间的相互作用。
通过行为型设计模式,可以更加清晰的划分类和对象的职责,并研究系统在运行时不同实例对象之间的交互。在系统运行的过程中,对象的存在并不是孤立的,它可以通过相互通信和协作来完成某些复杂的功能,一个对象的运行也会影响到其他的对象。
行为型设计模式可以分为类行为型和对象行为型。
- 类行为型,通过类的继承关系来在类之间分配行为,主要利用了多态的方式来实现
- 对象行为型,主要通过对象之间的关联关系来实现行为的分配,根据“合成复用原则”,一个系统中尽量使用关联关系来代替继承关系,所以常见的行为型就是对象行为型设计模式。
职责链模式
引子
在斗地主游戏中,上家出一张牌以后,下家查看手牌,如果要不起则将出牌的请求传递给他的下家,下家再次判断。如果一个循环结束,其他人都要不起这张牌,那么上家可以继续出牌。在这个过程中,出牌的请求沿着一条链传递,链上的每一位玩家都可以处理这个请求或者放弃这个请求继续传递。
模式动机
很多情况下,一个系统中处理某个请求的对象不止一个,那么我们可以构建一个链式结构,让请求沿着这条链进行传播,这条链就成为职责链。
职责链可以有很多形式,直线、环、树形,但是常见的就是直线型的链来传递请求。
描述:链上的每一个对象都是请求的处理者,职责链将可以处理请求的处理者组织成一条链,让请求在链上传播,由链上的处理者处理这个请求。客户端只要将请求发送到链上即可,不需要关系具体的处理细节和请求的传递,实现了请求发送者和请求处理者的解耦。
模式结构和说明
- Handler:抽象处理者角色,定义了一个处理请求的抽象方法,由具体处理者角色去实现这个方法。因为每一个处理者的下家还是一个处理者,所以定义了一个抽象处理者对象的引用来作为其对下家的引用。通过这个引用可以让处理者形成一条链。
- ConcereHandler:具体处理者对象,实现请求处理方法。在处理请求前判断是否有权限来处理请求,如果有则处理,如果没有则将请求传递给下一个处理者。通过下一个处理者的引用来转发请求。
设计
核心的类就是抽象处理者类的设计:
public abstract class Handler {
//protected 子类可访问
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(String request);
}
具体抽象者类的设计:
public class ConcreteHandler extends Handler{
@Override
public void handleRequest(String request) {
if (请求是否满足条件) {
//处理请求
} else {
this.successor.handleRequest(request);//转发请求
}
}
}
示例
场景:员工请假的时候,如果天数day < 3,主任可审批;3<=day<10经理可以审批;day > 10提示拒绝请求。
首先是请假条:
package design_model.dutyline;
public class LeaveRequest {
private String name;
private int day;
public LeaveRequest(String reason, int day) {
this.name = reason;
this.day = day;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}
抽象处理者类:
public abstract class Leader {
protected String name;
protected Leader successor;
public Leader(String name) {
this.name = name;
}
public void setSuccessor(Leader successor) {
this.successor = successor;
}
public abstract void handleRequest(LeaveRequest request);
}
具体的处理者类:
public class Director extends Leader {
public Director(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getDay() < 3) {
System.out.println("主任" + name + "审批员工" + request.getName() + "的请假条,请假天数为" + request.getDay() + "天。");
} else {
if (this.successor != null) {
this.successor.handleRequest(request);
}
}
}
}
public class Manager extends Leader {
public Manager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getDay() >= 3 && request.getDay() < 10) {
System.out.println("经理" + name + "审批员工" + request.getName() + "的请假条,请假天数为" + request.getDay() + "天。");
} else {
System.out.println("员工" + request.getName() + "竟然想请假 " + request.getDay() + " 天,不可能的!");
}
}
}
客户端类:
public class Client {
public static void main(String[] args) {
Leader director,manager;
director = new Director("王某某");
manager = new Manager("李三");
director.setSuccessor(manager);
LeaveRequest lr = new LeaveRequest("老王", 2);
director.handleRequest(lr);
LeaveRequest lr2 = new LeaveRequest("老李", 5);
director.handleRequest(lr2);
LeaveRequest lr3 = new LeaveRequest("老张", 20);
director.handleRequest(lr3);
}
}
//输出结果:
主任王某某审批员工老王的请假条,请假天数为2天。
经理李三审批员工老李的请假条,请假天数为5天。
员工老张竟然想请假 20 天,不可能的!
注:客户端负责职责链的创建
优缺点
优点:
- 接收方和发送方都不需要明确对方的状态,只需要知道一个请求最终会被处理即可
- 一个处理者对象只需要维护它的后继处理者对象的引用即可
- 可以动态的增加或修改处理者的请求处理方式
- 需要动态增加一个处理者时仅修改客户端代码即可
缺点:
- 如果没有一个明确的处理者,一个请求不一定能得到处理
- 如果职责链过长的话,系统性能会收到一定影响,而且调试比较复杂
- 如果建立职责链不当的话,可能会造成死循环
适用场景
- 一个请求有多个对象可以处理,具体哪个对象进行处理可以在运行时确定,客户端只需要把它提交到链上,而不需要关系是哪个对象处理了这个请求
- 在不确定指定接收者的情况下,将请求提交给多个请求处理者中的一个
- 可以动态的指定一组对象处理这个请求,还可以调整请求处理的次序
常见的使用场景:
- java的异常处理
try {
} catch (ArrayIndexOutOfBoundsException e) {
} catch (ArithmeticException e) {
} catch (Exception e) {
}
模式扩展
- 纯的职责链模式:即每个请求要么被全部处理,要么将请求传递给下一个处理者。
- 不纯的职责链模式:每一个请求处理者可以处理部分请求,然后将剩下的传递给下一个处理者