1.行为型模式
在软件运行时,对象不是孤立的,他们通过相互通信协作完成某种功能,一个对象在运行时也会影响其他对象的运行。
行为型模式关注系统中对象之间的交互,研究系统在运行时对象之间的相互通信与协作,进一步明确对象的职责。
行为型模式分为类行为型模式和对象行为型模式两种,其中类行为模式使用继承关系在几个类之间分配行为,主要通过多态等方式来分配父类与子类的职责。而对象行为型模式则使用对象的关联关系来分配行为,主要通过对象关联等方式来分配两个或多个类的职责。
(后续我们会学习11个设计模式均属于行为型模式)
2.职责链模式概述
奖学金申请,经过辅导员,系主任,院长,校长等多个环境,最后由校长确定是否授予奖学金。奖学金申请表是一个对象,后面的各个审批者构成一个链式结构,申请表沿着这条链进行传递,这条链被称为职责链。
职责链可以是一条直线、一个环、一个树形结构,最常见的是直线型。链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无需关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,将请求的发送者和请求的处理者解耦,这就是职责链模式的模式动机。
3.职责链模式结构
(1)Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。每一个处理者的下家还是一个处理者,故在抽象处理者中定义了一个抽象处理者类型的对象作为其对下家的引用,通过该引用处理者可以连成一条链。
(2)ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求。
4.职责链模式实现
(1)抽象处理者
/**
* 抽象处理者
*/
public abstract class Handler {
//维持对下家的引用
protected Handler successor;
public void setSuccessor(Handler successor){
this.successor = successor;
}
public abstract void handleRequest(String request);
}
(2)具体处理者类
/**
* 具体处理者类
*/
public class ConcreteHandler extends Handler {
@Override
public void handleRequest(String request) {
if(请求满足条件){
//处理请求
}else{
this.successor.handleRequest(request);//请求转发
}
}
}
(3)客户端
public class Client {
public static void main(String[] args) {
//...
Handler handler1,handler2,handler3;
handler1 = new ConcreteHandlerA();
handler2 = new ConcreteHandlerB();
handler3 = new ConcreteHandlerC();
//创建职责链
handler1.setSuccessor(handler2);
handler2.setSuccessor(handler3);
//发送请求,请求对象通常为自定义类型
handler1.handleRequest("请求对象");
}
}
5.职责链实例——采购根据金额需要走不同的流程
(1)采购单类,充当请求类
/**
* 采购单类,充当请求类
*/
public class PurchaseRequest {
private double amount;//采购金额
private int number;//采购单号
private String purpose;//采购目的
public PurchaseRequest(double amount,int number,String purpose){
this.amount = amount;
this.number = number;
this.purpose = purpose;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
}
(2)审批者类,充当抽象处理者
/**
* 审批者类,充当抽象处理者
*/
public abstract class Approver {
protected Approver successor;//定义后继对象
protected String name;
public Approver(String name){
this.name = name;
}
//设置后继者
public void setSuccessor(Approver successor) {
this.successor = successor;
}
//抽象请求处理方法
public abstract void processRequest(PurchaseRequest request);
}
(3)主任类,充当具体处理者
/**
* 主任类,充当具体处理者
*/
public class Director extends Approver {
public Director(String name) {
super(name);
}
/**
* 具体请求处理方法
* @param request
*/
@Override
public void processRequest(PurchaseRequest request) {
if(request.getAmount()<50000){
//处理请求
System.out.println("主任"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+"元,采购目的:"+request.getPurpose()+".");
}else {
this.successor.processRequest(request);//转发请求
}
}
}
(4)副董事长类,充当具体处理者
/**
* 副董事长类,充当具体处理者
*/
public class VicePresident extends Approver {
public VicePresident(String name) {
super(name);
}
/**
* 具体请求处理方法
* @param request
*/
@Override
public void processRequest(PurchaseRequest request) {
if(request.getAmount()<100000){
//处理请求
System.out.println("副董事长"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+"元,采购目的:"+request.getPurpose()+".");
}else {
this.successor.processRequest(request);//转发请求
}
}
}
(5)董事长类,充当具体处理者
/**
* 董事长类,充当具体处理者
*/
public class President extends Approver {
public President(String name) {
super(name);
}
/**
* 具体请求处理方法
* @param request
*/
@Override
public void processRequest(PurchaseRequest request) {
if(request.getAmount()<500000){
//处理请求
System.out.println("董事长"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+"元,采购目的:"+request.getPurpose()+".");
}else {
this.successor.processRequest(request);//转发请求
}
}
}
(6)董事会类,充当具体处理者
/**
* 董事会类,充当具体处理者
*/
public class Congress extends Approver {
public Congress(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
//处理请求
System.out.println("召开董事会审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+"元,采购目的:"+request.getPurpose()+".");
}
}
(7)客户端
public class Client {
public static void main(String[] args) {
Approver wjzhang,gyang,jguo,meeting;
wjzhang = new Director("张无忌");
gyang = new VicePresident("杨过");
jguo = new President("郭靖");
meeting = new Congress("董事会");
//创建职责链
wjzhang.setSuccessor(gyang);
gyang.setSuccessor(jguo);
jguo.setSuccessor(meeting);
//创建采购单
PurchaseRequest pr1 = new PurchaseRequest(45000,10001,"购买倚天剑");
wjzhang.processRequest(pr1);
PurchaseRequest pr2 = new PurchaseRequest(60000,10002,"购买葵花宝典");
wjzhang.processRequest(pr2);
PurchaseRequest pr3 = new PurchaseRequest(160000,10003,"购买金刚经");
wjzhang.processRequest(pr3);
PurchaseRequest pr4 = new PurchaseRequest(800000,10004,"购买桃花岛");
wjzhang.processRequest(pr4);
}
}
(8)运行结果及路径
6.纯与不纯的职责链
(1)纯的职责链模式
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个,要么承担全部责任,要么将责任推给下家。而且在纯的职责链模式中要求一个请求必须被某一个处理者对象所接受,不能出现某个请求未被任何一个处理者对象处理的情况。
(2)不纯的职责链模式
在一个不纯的职责链模式中允许某个请求呗一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接受并处理。
java AWT1.0中的时间处理模型应用的是不纯的职责链模式,其基本原理如下:
由于窗口组件一般位于容器组件中,因此当事件发生在某一个组件上时先通过组件对象的handleEvent()方法将事件传递给相应的事件处理方法,该事件处理方法将处理此事件,然后决定是否将该事件向上级容器组件传播,如此反复,直到事件到达顶层容器组件为止。如果一直传到最顶层容器仍没有处理方法,则该事件不予处理。
每一级组件在接收到事件时都可以处理此事件,而不论此事件是否在上一级已得到处理,还存在事件未被处理的情况。
早期,这种事件处理机制又叫做事件浮升机制,后来使用观察者模式代替职责链模式来处理事件。目前,javaScript仍使用事件浮升机制来处理事件。
7.职责链模式优缺点
优:
(1)使一个对象无需知道其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可。降低耦合度
(2)请求处理对象仅需维持一个指向其后继者的引入,简化对象之间的连接
(3)在给对象分派职责时,职责链可以带来更多的灵活性
(4)新增具体处理者无需修改原有代码
缺:
(1)请求可能末端得不到处理
(2)性能受一定影响,代码调试不方便
(3)有可能会陷入死循环
8.使用环境
(1)多个对象处理同一个请求,具体哪个对象处理该请求待运行时在确定,客户端只需要吧请求提交到链上,无需关心谁去处理
(2)在不明确指定接收者的情况下向多个对象中的一个提交一个请求
(3)可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序