职责链模式

《大话设计模式》第24章读书笔记,介绍职责链模式

Posted by GrayWind on November 21, 2018

职责链模式(Chain of Responsibility)使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条炼,并沿着这条链传递该请求,直到有一个对象处理它为止。

chain

Handler类,定义一个处理请示的接口

public abstract class Handler {
	protected Handler successor;

	// 设置后继者
	public void setSuccessor(Handler successor) {
		this.successor = successor;
	}

	// 处理请求
	public abstract void handleRequest(int request);
}

ConcreteHandler类,具体处理者类,处理它所负责的请求,可访问它的后继者,如果可处理该请求,就处理之,否则就将该请求转发给它的后继者。

ConcreteHandler1、ConcreteHandler2、ConcreteHandler3分别有权处理数在不同区间内的请求,无权则转到下一位

public class ConcreteHandler1 extends Handler {

	@Override
	public void handleRequest(int request) {
		if (request >= 0 && request < 10) {
			System.out.printf("%s  处理请求  %d\n", this.getClass().getName(), request);
		} else if (successor != null) {
			successor.handleRequest(request);
		}
	}

}

public class ConcreteHandler2 extends Handler {

	@Override
	public void handleRequest(int request) {
		if (request >= 10 && request < 20) {
			System.out.printf("%s  处理请求  %d\n", this.getClass().getName(), request);
		} else if (successor != null) {
			successor.handleRequest(request);
		}
	}

}

public class ConcreteHandler3 extends Handler {

	@Override
	public void handleRequest(int request) {
		if (request >= 20 && request < 30) {
			System.out.printf("%s  处理请求  %d\n", this.getClass().getName(), request);
		} else if (successor != null) {
			successor.handleRequest(request);
		}
	}

}

客户端代码,向链上的具体处理者对象提交请求

public class ChainTest {
	public static void main(String[] args) {
		Handler h1 = new ConcreteHandler1();
		Handler h2 = new ConcreteHandler2();
		Handler h3 = new ConcreteHandler3();
		h1.setSuccessor(h2);
		h2.setSuccessor(h3);

		int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };

		for (int request : requests) {
			h1.handleRequest(request);
		}

	}
}

运行结果

graywind.design.chain.ConcreteHandler1  处理请求  2
graywind.design.chain.ConcreteHandler1  处理请求  5
graywind.design.chain.ConcreteHandler2  处理请求  14
graywind.design.chain.ConcreteHandler3  处理请求  22
graywind.design.chain.ConcreteHandler2  处理请求  18
graywind.design.chain.ConcreteHandler1  处理请求  3
graywind.design.chain.ConcreteHandler3  处理请求  27
graywind.design.chain.ConcreteHandler3  处理请求  20

职责链模式中最关键的是当客户提交一个请求时,请求是沿着链传递直至有一个ConcreteHandler对象负责处理它。这就使得接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构,结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需要保持它所有的候选接受者的引用,大大降低了耦合度。我们可以随时增加或修改处理一个请求的结构,增强了给对象指派职责的灵活性。但是,一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置得不到处理。


现在以公司的审批流程为例,管理者分为经理、总监、总经理三个级别,他们分别可以

请求类如下

public class Request {
	// 申请类别
	private String requestType;

	// 申请内容
	private String requestContent;

	// 数量
	private int number;

	public String getRequestType() {
		return requestType;
	}

	public void setRequestType(String requestType) {
		this.requestType = requestType;
	}

	public String getRequestContent() {
		return requestContent;
	}

	public void setRequestContent(String requestContent) {
		this.requestContent = requestContent;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}
}

抽象的管理者接口

public abstract class Manager {
	protected String name;
	//管理者的上级
    protected Manager superior;

    public Manager(String name)
    {
        this.name = name;
    }

    //设置管理者的上级
    public void setSuperior(Manager superior)
    {
        this.superior = superior;
    }

    //申请请求
    abstract public void requestApplications(Request request);
}

经理CommonManager可以审批两天内的假期

public class CommonManager extends Manager {

	public CommonManager(String name) {
		super(name);
	}

	@Override
	public void requestApplications(Request request) {
		if ("请假".equals(request.getRequestType()) && request.getNumber() <= 2) {
			System.out.printf("%s:%s 数量%d 被批准\n", name, request.getRequestContent(), request.getNumber());
		} else {
			if (superior != null)
				superior.requestApplications(request);
		}
	}

}

总监Majordomo可以审批一周内的假期

public class Majordomo extends Manager {

	public Majordomo(String name) {
		super(name);
	}

	@Override
	public void requestApplications(Request request) {
		if ("请假".equals(request.getRequestType()) && request.getNumber() <= 5) {
			System.out.printf("%s:%s 数量%d 被批准\n", name, request.getRequestContent(), request.getNumber());
		} else {
			if (superior != null)
				superior.requestApplications(request);
		}
	}

}

总经理全都可以审批

public class GeneralManager extends Manager {

	public GeneralManager(String name) {
		super(name);
	}

	@Override
	public void requestApplications(Request request) {
		if ("请假".equals(request.getRequestType())) {
			System.out.printf("%s:%s 数量%d 被批准\n", name, request.getRequestContent(), request.getNumber());
		} else if (request.getRequestType() == "加薪" && request.getNumber() <= 500) {
			System.out.printf("%s:%s 数量%d 被批准\n", name, request.getRequestType(), request.getNumber());
		} else if (request.getRequestType() == "加薪" && request.getNumber() > 500) {
			System.out.printf("%s:%s 数量%d 再说吧\n", name, request.getRequestType(), request.getNumber());
		}
	}

}

客户端代码中,所有请求是由经理发起的,但具体由谁来处理客户端不知道

public class Test {
	public static void main(String[] args) {
		CommonManager jinli = new CommonManager("金利");
        Majordomo zongjian = new Majordomo("宗剑");
        GeneralManager zhongjingli = new GeneralManager("钟精励");
        jinli.setSuperior(zongjian);
        zongjian.setSuperior(zhongjingli);

        Request request = new Request();
        request.setRequestType("请假");
        request.setRequestContent("小菜请假");
        request.setNumber(1);
        jinli.requestApplications(request);//金利:小菜请假 数量1 被批准

        Request request2 = new Request();
        request2.setRequestType("请假");
        request2.setRequestContent("小菜请假");
        request2.setNumber(4);
        jinli.requestApplications(request2);//宗剑:小菜请假 数量4 被批准

        Request request3 = new Request();
        request3.setRequestType("加薪");
        request3.setRequestContent("小菜请求加薪");
        request3.setNumber(500);
        jinli.requestApplications(request3);//钟精励:加薪 数量500 被批准

        Request request4 = new Request();
        request4.setRequestType("加薪");
        request4.setRequestContent("小菜请求加薪");
        request4.setNumber(1000);
        jinli.requestApplications(request4);//钟精励:加薪 数量1000 再说吧
	}
}