Java中责任链模式的作用有哪些
本篇文章給大家分享的是有關Java中責任鏈模式的作用有哪些,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
應用場景:
為完成同一個請求,如果存在多個請求處理器以及未知請求處理器個數或者請求處理器可動態配置的情況下,可以考慮使用責任鏈模式。如OKHttp的攔截器就是使用的責任鏈模式。
實例UML圖:
實例執行流程圖:
實例:
1、實例場景
在公司內部員工請假一般情況是這樣的:員工在OA系統中提交一封請假郵件,該郵件會自動轉發到你的直接上級領導郵箱里,如果你的請假的情況特殊的話,該郵件也會轉發到你上級的上級的郵箱,根據請假的情況天數多少,系統會自動轉發相應的責任人的郵箱。我們就以這樣一種場景為例完成一個責任鏈模式的代碼。為了更清晰的描述這種場景我們規定如下:
① GroupLeader(組長 ):他能批準的假期為2天,如果請假天數超過2天就將請假郵件自動轉發到組長和經理郵箱。
② Manager(經理):他能批準的假期為4天以內,如果請假天數大于4天將該郵件轉發到自動轉發到組長、經理和部門領導的郵箱。
③ DepartmentHeader(部門領導):他能批準的假期為7天以內,如果大于7天就只批準7天。
2、實例代碼
我們清楚了上面的場景以后就開始定義模型:
①根據面向對象的思想我們得定義需要用到的對象。OK,為了更加清楚的說明“責任鏈模式的可擴展性”問題我這里采用了建造者模式構造Request對象,“請假”對象Request如下:
/**
*類描述:請假對象
*
*@authorlzy
*/
publicclassRequest{
privateStringname;
privateStringreason;
privateintdays;
privateStringgroupLeaderInfo;
privateStringmanagerInfo;
privateStringdepartmentHeaderInfo;
privateStringcustomInfo;
publicRequest(Builderbuilder){
super();
this.name=builder.name;
this.reason=builder.reason;
this.days=builder.days;
this.groupLeaderInfo=builder.groupLeaderInfo;
this.managerInfo=builder.managerInfo;
this.departmentHeaderInfo=builder.departmentHeaderInfo;
this.customInfo=builder.customInfo;
}
publicstaticclassBuilder{
publicStringname;
publicStringreason;
publicintdays;
publicStringgroupLeaderInfo;
publicStringmanagerInfo;
publicStringdepartmentHeaderInfo;
publicStringcustomInfo;
publicBuilder(){
}
publicBuildersetName(Stringname){
this.name=name;
returnthis;
}
publicBuildersetReason(Stringreason){
this.reason=reason;
returnthis;
}
publicBuildersetDays(intdays){
this.days=days;
returnthis;
}
publicBuildersetGroupLeaderInfo(StringgroupLeaderInfo){
this.groupLeaderInfo=groupLeaderInfo;
returnthis;
}
publicBuildersetManagerInfo(StringmanagerInfo){
this.managerInfo=managerInfo;
returnthis;
}
publicBuildersetDepartmentHeaderInfo(StringdepartmentHeaderInfo){
this.departmentHeaderInfo=departmentHeaderInfo;
returnthis;
}
publicBuildersetCustomInfo(StringcustomInfo){
this.customInfo=customInfo;
returnthis;
}
publicBuildernewRequest(Requestrequest){
this.name=request.name;
this.days=request.days;
this.reason=request.reason;
if(request.groupLeaderInfo!=null
&&!request.groupLeaderInfo.equals("")){
this.groupLeaderInfo=request.groupLeaderInfo;
}
if(request.managerInfo!=null&&!request.managerInfo.equals("")){
this.managerInfo=request.managerInfo;
}
if(request.departmentHeaderInfo!=null
&&!request.departmentHeaderInfo.equals("")){
this.departmentHeaderInfo=request.departmentHeaderInfo;
}
if(request.customInfo!=null&&!request.customInfo.equals("")){
this.customInfo=request.customInfo;
}
returnthis;
}
publicRequestbuild(){
returnnewRequest(this);
}
}
publicStringname(){
returnname;
}
publicStringreason(){
returnreason;
}
publicintdays(){
returndays;
}
publicStringgroupLeaderInfo(){
returngroupLeaderInfo;
}
publicStringmanagerInfo(){
returnmanagerInfo;
}
publicStringdepartmentHeaderInfo(){
returndepartmentHeaderInfo;
}
publicStringcustomInfo(){
returncustomInfo;
}
@Override
publicStringtoString(){
return"Request[name="+name+",reason="+reason+",days="
+days+",customInfo="+customInfo+",groupLeaderInfo="
+groupLeaderInfo+",managerInfo="+managerInfo
+",departmentHeaderInfo="+departmentHeaderInfo+"]";
}
}
接下來再定義“批準結果”對象Result:
/**
*類描述:結果對象
*
*@authorlzy
*
*/
publicclassResult{
publicbooleanisRatify;
publicStringinfo;
publicResult(){
}
publicResult(booleanisRatify,Stringinfo){
super();
this.isRatify=isRatify;
this.info=info;
}
publicbooleanisRatify(){
returnisRatify;
}
publicvoidsetRatify(booleanisRatify){
this.isRatify=isRatify;
}
publicStringgetReason(){
returninfo;
}
publicvoidsetReason(Stringinfo){
this.info=info;
}
@Override
publicStringtoString(){
return"Result[isRatify="+isRatify+",info="+info+"]";
}
}
②我們接下來再來定義一個接口,這個接口用于處理Request和獲取請求結果Result。
/**
*接口描述:處理請求
*
*@authorlzy
*
*/
publicinterfaceRatify{
//處理請求
publicResultdeal(Chainchain);
/**
*接口描述:對request和Result封裝,用來轉發
*/
interfaceChain{
//獲取當前request
Requestrequest();
//轉發request
Resultproceed(Requestrequest);
}
}
看到上面的接口,可能會有人迷惑:在接口Ratify中為什么又定義一個Chain接口呢?其實這個接口是單獨定義還是內部接口沒有太大關系,但是考慮到Chain接口與Ratify接口的關系為提高內聚性就定義為內部接口了。定義Ratify接口是為了處理Request那為什么還要定義Chain接口呢?這正是責任鏈接口的精髓之處:轉發功能及可動態擴展“責任人”,這個接口中定義了兩個方法一個是request()就是為了獲取request,如果當前Ratify的實現類獲取到request之后發現自己不能處理或者說自己只能處理部分請求,那么他將自己的那部分能處理的就處理掉,然后重新構建一個或者直接轉發Request給下一個責任人??赡苓@點說的不容易理解,我舉個例子,在Android與后臺交互中如果使用了Http協議,當然我們可能使用各種Http框架如HttpClient、OKHttp等,我們只需要發送要請求的參數就直接等待結果了,這個過程中你可能并沒有構建請求頭,那么框架幫你把這部分工作給做了,它做的工程中如果使用了責任鏈模式的話,它肯定會將Request進行包裝(也就是添加請求頭)成新的Request,我們姑且加他為Request1,如果你又希望Http做本地緩存,那么Request1又會被轉發到并且重新進一步包裝為Request2??傊瓹hain這個接口就是起到對Request進行重新包裝的并將包裝后的Request進行下一步轉發的作用。如果還不是很明白也沒關系,本實例會演示這一功能機制。
③上面說Chain是用來對Request重新包裝以及將包裝后的Request進行下一步轉發用的,那我們就具體實現一下:
/**
*類描述:實現Chain的真正的包裝Request和轉發功能
*
*@authorlzy
*
*/
publicclassRealChainimplementsChain{
publicRequestrequest;
publicList<Ratify>ratifyList;
publicintindex;
/**
*構造方法
*
*@paramratifyList
*Ratify接口的實現類集合
*@paramrequest
*具體的請求Request實例
*@paramindex
*已經處理過該request的責任人數量
*/
publicRealChain(List<Ratify>ratifyList,Requestrequest,intindex){
this.ratifyList=ratifyList;
this.request=request;
this.index=index;
}
/**
*方法描述:具體轉發功能
*/
@Override
publicResultproceed(Requestrequest){
Resultproceed=null;
if(ratifyList.size()>index){
RealChainrealChain=newRealChain(ratifyList,request,index+1);
Ratifyratify=ratifyList.get(index);
proceed=ratify.deal(realChain);
}
returnproceed;
}
/**
*方法描述:返回當前Request對象或者返回當前進行包裝后的Request對象
*/
@Override
publicRequestrequest(){
returnrequest;
}
}
④ 經過上面幾步我們已經完成了責任鏈模式的核心功能,接下來我們定義幾個相關責任對象:GroupLeader、Manager和DepartmentHeader,并讓他們實現Ratify接口。
/**
*組長
*
*@authorlzy
*
*/
publicclassGroupLeaderimplementsRatify{
@Override
publicResultdeal(Chainchain){
Requestrequest=chain.request();
System.out.println("GroupLeader=====>request:"+request.toString());
if(request.days()>1){
//包裝新的Request對象
RequestnewRequest=newRequest.Builder().newRequest(request)
.setManagerInfo(request.name()+"平時表現不錯,而且現在項目也不忙")
.build();
returnchain.proceed(newRequest);
}
returnnewResult(true,"GroupLeader:早去早回");
}
}
/**
*經理
*
*@authorlzy
*
*/
publicclassManagerimplementsRatify{
@Override
publicResultdeal(Chainchain){
Requestrequest=chain.request();
System.out.println("Manager=====>request:"+request.toString());
if(request.days()>3){
//構建新的Request
RequestnewRequest=newRequest.Builder().newRequest(request)
.setManagerInfo(request.name()+"每月的KPI考核還不錯,可以批準")
.build();
returnchain.proceed(newRequest);
}
returnnewResult(true,"Manager:早點把事情辦完,項目離不開你");
}
}
/**
*部門領導
*
*@authorlzy
*
*/
publicclassDepartmentHeaderimplementsRatify{
@Override
publicResultdeal(Chainchain){
Requestrequest=chain.request();
System.out.println("DepartmentHeader=====>request:"
+request.toString());
if(request.days()>7){
returnnewResult(false,"你這個完全沒必要");
}
returnnewResult(true,"DepartmentHeader:不要著急,把事情處理完再回來!");
}
}
到此,責任鏈模式的一個Demo就算是完成了,但為了方便調用,我們在寫一個該責任鏈模式的客戶端工具類ChainOfResponsibilityClient 如下:
/**
*類描述:責任鏈模模式工具類
*
*@authorlzy
*
*/
publicclassChainOfResponsibilityClient{
privateArrayList<Ratify>ratifies;
publicChainOfResponsibilityClient(){
ratifies=newArrayList<Ratify>();
}
/**
*方法描述:為了展示“責任鏈模式”的真正的迷人之處(可擴展性),在這里構造該方法以便添加自定義的“責任人”
*
*@paramratify
*/
publicvoidaddRatifys(Ratifyratify){
ratifies.add(ratify);
}
/**
*方法描述:執行請求
*
*@paramrequest
*@return
*/
publicResultexecute(Requestrequest){
ArrayList<Ratify>arrayList=newArrayList<Ratify>();
arrayList.addAll(ratifies);
arrayList.add(newGroupLeader());
arrayList.add(newManager());
arrayList.add(newDepartmentHeader());
RealChainrealChain=newRealChain(this,arrayList,request,0);
returnrealChain.proceed(request);
}
}
OK,我們測試一下見證奇跡吧:
/**
*類描述:責任鏈模式測試類
*
*@authorlzy
*
*/
publicclassMain{
publicstaticvoidmain(String[]args){
Requestrequest=newRequest.Builder().setName("張三").setDays(5)
.setReason("事假").build();
ChainOfResponsibilityClientclient=newChainOfResponsibilityClient();
Resultresult=client.execute(request);
System.out.println("結果:"+result.toString());
}
}
這個請求是張三請事假5天,按照我們的約定應該請求會到達部門領導手里,且他看到請求的樣式為:“ [name=張三, reason=事假, days=5customInfo=null, groupLeaderInfo=張三平時表現不錯,而且現在項目也不忙, managerInfo=張三每月的KPI考核還不錯,可以批準, departmentHeaderInfo=null]”
我們看一下打印的日志:
GroupLeader=====>request:Request [name=張三, reason=事假, days=5customInfo=null, groupLeaderInfo=null, managerInfo=null, departmentHeaderInfo=null]
Manager=====>request:Request [name=張三, reason=事假, days=5customInfo=null, groupLeaderInfo=張三平時表現不錯,而且現在項目也不忙, managerInfo=null, departmentHeaderInfo=null]
DepartmentHeader=====>request:Request [name=張三, reason=事假, days=5customInfo=null, groupLeaderInfo=張三平時表現不錯,而且現在項目也不忙, managerInfo=張三每月的KPI考核還不錯,可以批準, departmentHeaderInfo=null]
結果:Result [isRatify=true, info=DepartmentHeader:不要著急,把事情處理完再回來!]
OK,和預期一樣完美。剛開始就提到這個責任鏈模式是可以“動態擴展的”,我們驗證一下,首先自定義一個“責任人”(其實也可以叫攔截器):
/**
*類描述:自定義“責任人”
*
*@authorlzy
*
*/
publicclassCustomInterceptorimplementsRatify{
@Override
publicResultdeal(Chainchain){
Requestrequest=chain.request();
System.out.println("CustomInterceptor=>"+request.toString());
Stringreason=request.reason();
if(reason!=null&&reason.equals("事假")){
RequestnewRequest=newRequest.Builder().newRequest(request)
.setCustomInfo(request.name()+"請的是事假,而且很著急,請領導重視一下")
.build();
System.out.println("CustomInterceptor=>轉發請求");
returnchain.proceed(newRequest);
}
returnnewResult(true,"同意請假");
}
}
然后在測試類Main.java中調用如下:
/**
*類描述:責任鏈模式測試類
*
*@authorlzy
*
*/
publicclassMain{
publicstaticvoidmain(String[]args){
Requestrequest=newRequest.Builder().setName("張三").setDays(5)
.setReason("事假").build();
ChainOfResponsibilityClientclient=newChainOfResponsibilityClient();
client.addRatifys(newCustomInterceptor());
Resultresult=client.execute(request);
System.out.println("結果:"+result.toString());
}
}
OK,看一下日志:
總結
以上是生活随笔為你收集整理的Java中责任链模式的作用有哪些的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图论——Tarjan 初步 DFS序+时
- 下一篇: 洛谷2014 选课(树形DP)树形背包问