1.1 老板,我要加薪
"我和刚进来的几个同事比较,我觉得我做得很好。公司每每分配的任务,我基本都可以快速完成。有一次,一段程序需要增加一个分支条件,我立刻想到利用反射、工厂等设计模式来处理,经理对我的设计很满意。" 我要求转正加薪。
1.2 加薪代码初步
加薪代码实现,无论加薪还是请假,都是一种申请,申请就应该有申请类别,申请内容和申请数量。然后我觉得经理,总监,总经理都是管理者,应该对申请流程作出判断,是否有权决策。
package code.chapter24.chainofresponsibility1;
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
Manager manager = new Manager("金利");
Manager director = new Manager("宗剑");
Manager generalManager = new Manager("钟精励");
Request request = new Request();
request.setRequestType("加薪");
request.setRequestContent("小菜请求加薪");
request.setNumber(10000);
manager.getResult("经理", request);
director.getResult("总监", request);
generalManager.getResult("总经理", request);
Request request2 = new Request();
request2.setRequestType("请假");
request2.setRequestContent("小菜请假");
request2.setNumber(3);
manager.getResult("经理", request2);
director.getResult("总监", request2);
generalManager.getResult("总经理", request2);
System.out.println();
System.out.println("**********************************************");
}
}
//申请
class Request {
//申请类别
private String requestType;
public String getRequestType(){
return this.requestType;
}
public void setRequestType(String value){
this.requestType = value;
}
//申请内容
private String requestContent;
public String getRequestContent(){
return this.requestContent;
}
public void setRequestContent(String value){
this.requestContent = value;
}
//数量
private int number;
public int getNumber(){
return this.number;
}
public void setNumber(int value){
this.number = value;
}
}
//管理者
class Manager{
protected String name;
public Manager(String name){
this.name = name;
}
public void getResult(String managerLevel,Request request){
if (managerLevel == "经理"){
if (request.getRequestType()=="请假" && request.getNumber()<=2)
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,被批准");
else
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,我无权处理");
}
else if (managerLevel == "总监"){
if (request.getRequestType()=="请假" && request.getNumber()<=5)
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,被批准");
else
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,我无权处理");
}
else if (managerLevel == "总经理"){
if (request.getRequestType()=="请假")
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,被批准");
else if (request.getRequestType()=="加薪" && request.getNumber()<=5000)
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"元,被批准");
else if (request.getRequestType()=="加薪" && request.getNumber()>5000)
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"元,再说吧");
}
}
}
"那个'管理者'类吧,里面的'结果'方法比较长,加上有太多的分支判断,这其实是非常不好的设计。"
"说得不错,因为你很难讲当中还会不会增加其他的管理类别,比如项目经理、部门经理、人力总监、副总经理等。那就意味着都需要去更改这个类,这个类承担了太多的责任,这违背了哪些设计原则?"
"类有太多的责任,这违背了单一职责原则,增加新的管理类别,需要修改这个类,违背了开放-封闭原则。"
"说得好,那你觉得应该如何下手去重构它呢?"
"你刚才提到了可能会增加管理类别,那就意味着这里容易变化,我想把这些公司管理者的类别分别做成管理者的子类,这就可以利用多态性来化解分支带来的僵化。"
"那如何解决经理无权上报总监,总监无权再上报总经理这样的功能呢?"
"我想让它们之间有一定的关联,把用户的请求传递,直到可以解决这个请求为止。"
"说得不错,你其实已经说到了一个行为设计模式'职责链模式'的意图了。"
1.3 责任链模式
职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。[DP]
"这里发出这个请求的客户端并不知道这当中的哪一个对象最终处理这个请求,这样系统的更改可以在不影响客户端的情况下动态地重新组织和分配责任。"
"听起来感觉不错哦,但如何做呢?"
"我们来看看结构图。"
职责链模式(Chain of Responsibility)结构图
package code.chapter24.chainofresponsibility0;
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
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);
}
System.out.println();
System.out.println("**********************************************");
}
}
abstract class Handler{
protected Handler successor;
//设置继任者
public void setSuccessor(Handler successor){
this.successor = successor;
}
public abstract void handleRequest(int request);
}
class ConcreteHandler1 extends Handler{
public void handleRequest(int request){
if (request >=0 && request < 10){
System.out.println(this.getClass().getSimpleName()+" 处理请求 "+request);
}
else if (successor != null){
successor.handleRequest(request);
}
}
}
class ConcreteHandler2 extends Handler{
public void handleRequest(int request){
if (request >=10 && request < 20){
System.out.println(this.getClass().getSimpleName()+" 处理请求 "+request);
}
else if (successor != null){
successor.handleRequest(request);
}
}
}
class ConcreteHandler3 extends Handler{
public void handleRequest(int request){
if (request >=20 && request < 30){
System.out.println(this.getClass().getSimpleName()+" 处理请求 "+request);
}
else if (successor != null){
successor.handleRequest(request);
}
}
}
Handler类,定义一个处理请示的接口。
ConcreteHandler类,具体处理者类,处理它所负责的请求,可访问它的后继者,如果可处理该请求,就处理之,否则就将该请求转发给它的后继者。
ConcreteHandler1,当请求数为0~10则有权处理,否则转到下一位。
ConcreteHandler2,当请求数为10~20则有权处理,否则转到下一位。
ConcreteHandler3,当请求数为20~30则有权处理,否则转到下一位。
客户端代码,向链上的具体处理者对象提交请求。
1.4 责任链模式的好处
"这当中最关键的是当客户提交一个请求时,请求是沿链传递直至有一个ConcreteHandler对象负责处理它。[DP]"
"这样做的好处是不是说请求者不用管哪个对象来处理,反正该请求会被处理就对了?"
"是的,这就使得接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用[DP]。这也就大大降低了耦合度了。"
"我感觉由于是在客户端来定义链的结构,也就是说,我可以随时地增加或修改处理一个请求的结构。增强了给对象指派职责的灵活性[DP]。"
"是的,这的确是很灵活,不过也要当心,一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理,这就很糟糕了。需要事先考虑全面。"
"哈,这就跟现实中邮寄一封信,因地址不对,最终无法送达一样。"
"是的,就是这个意思。就刚才的例子而言,最重要的有两点,一个是你需要事先给每个具体管理者设置他的上司是哪个类,也就是设置后继者。另一点是你需要在每个具体管理者处理请求时,做出判断,是可以处理这个请求,还是必须要'推卸责任',转移给后继者去处理。"
"哦,我明白你的意思了,其实就是把我现在写的这个管理者类当中的那些分支,分解到每一个具体的管理者类当中,然后利用事先设置的后继者来实现请求处理的权限问题。"
1.5 加薪代码重构
"是的,所以我们先来改造这个管理者类,此时它将成为抽象的父类了,其实它就是Handler。"
代码结构图
package code.chapter24.chainofresponsibility2;
public class Test {
public static void main(String[] args) {
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
CommonManager manager = new CommonManager("金利");
Director director = new Director("宗剑");
GeneralManager generalManager = new GeneralManager("钟精励");
manager.setSuperior(director);
director.setSuperior(generalManager);
Request request = new Request();
request.setRequestType("请假");
request.setRequestContent("小菜请假");
request.setNumber(1);
manager.requestApplications(request);
Request request2 = new Request();
request2.setRequestType("请假");
request2.setRequestContent("小菜请假");
request2.setNumber(4);
manager.requestApplications(request2);
Request request3 = new Request();
request3.setRequestType("加薪");
request3.setRequestContent("小菜请求加薪");
request3.setNumber(5000);
manager.requestApplications(request3);
Request request4 = new Request();
request4.setRequestType("加薪");
request4.setRequestContent("小菜请求加薪");
request4.setNumber(10000);
manager.requestApplications(request4);
System.out.println();
System.out.println("**********************************************");
}
}
//申请
class Request {
//申请类别
private String requestType;
public String getRequestType(){
return this.requestType;
}
public void setRequestType(String value){
this.requestType = value;
}
//申请内容
private String requestContent;
public String getRequestContent(){
return this.requestContent;
}
public void setRequestContent(String value){
this.requestContent = value;
}
//数量
private int number;
public int getNumber(){
return this.number;
}
public void setNumber(int value){
this.number = value;
}
}
//管理者抽象类
abstract class Manager{
protected String name;
public Manager(String name){
this.name = name;
}
//设置管理者上级
protected Manager superior;
public void setSuperior(Manager superior){
this.superior = superior;
}
//请求申请
public abstract void requestApplications(Request request);
}
//普通经理
class CommonManager extends Manager{
public CommonManager(String name){
super(name);
}
public void requestApplications(Request request){
if (request.getRequestType()=="请假" && request.getNumber()<=2)
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,被批准");
else {
if (this.superior != null)
this.superior.requestApplications(request);
}
}
}
//总监
class Director extends Manager{
public Director(String name){
super(name);
}
public void requestApplications(Request request){
if (request.getRequestType()=="请假" && request.getNumber()<=5)
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,被批准");
else {
if (this.superior != null)
this.superior.requestApplications(request);
}
}
}
//总经理
class GeneralManager extends Manager{
public GeneralManager(String name){
super(name);
}
public void requestApplications(Request request){
if (request.getRequestType()=="请假"){
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"天,被批准");
}
else if (request.getRequestType()=="加薪" && request.getNumber()<=5000){
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"元,被批准");
}
else if (request.getRequestType()=="加薪" && request.getNumber()>5000){
System.out.println(this.name+":"+request.getRequestContent()+" 数量:"+request.getNumber()+"元,再说吧");
}
}
}
Request请求类与原来一样。
"经理类就可以去继承这个'管理者'类,只需重写'申请请求'的方法就可以了。"
"'总监'类同样继承'管理者类'。"
"'总经理'的权限就是全部都需要处理。"
"由于我们把你原来的一个'管理者'类改成了一个抽象类和三个具体类,此时类之间的灵活性就大大增加了,如果我们需要扩展新的管理者类别,只需要增加子类就可以。比如这个例子增加一个'集团总裁'类,完全是没有问题的,只需要修改'总经理类'即可,并不影响其他类代码。目前,还有一个关键,那就是客户端如何编写。"
"嗯,这的确是很好地解决了原来大量的分支判断造成难维护、灵活性差的问题。"
1.6 加薪成功
一段时间你的工作情况,你的积极表现和非常优秀的编程能力总经理也是非常肯定的。所以他最终答应了你的申请,给你加薪,从下个月开始实施。