“長(zhǎng)安回望繡成堆购撼,山頂千門次第開。一騎紅塵妃子笑匕累,無人知是荔枝來”陵刹。杜牧的《過華清宮》流傳千古,楊貴妃喜食荔枝也成為眾所周知的事情欢嘿。楊貴妃吃的荔枝必須在采摘后的幾天內(nèi)送到衰琐,如果超過了四五天,荔枝就會(huì)腐爛际插,在古代路途遙遠(yuǎn)和交通不便成為了致命傷碘耳,為了讓楊貴妃吃到新鮮的荔枝而不勞民傷財(cái),小Y決定讓楊貴妃和現(xiàn)代物流來一個(gè)偶遇框弛。
楊貴妃:大王,臣妾想吃新鮮可口的荔枝(一陣撒嬌聲捕捂,各位各自想象)瑟枫。
唐玄宗:“ok!No趴笨”指攒。然后馬上召來路人甲慷妙,讓路人甲無論如何都要在三天之內(nèi)把荔枝送來,不然以死謝罪允悦。
朝中大臣紛紛幸災(zāi)樂禍膝擂,覺得路人甲肯定會(huì)死無葬身之地的。但是路人甲胸有成竹的領(lǐng)命而去(路人甲之所以這么信心十足隙弛,是因?yàn)槁啡思自蒙衩馗呷薡指點(diǎn)架馋,說命中必有一劫,只有按照幾千年后的現(xiàn)代做法建一套有效的物流方法方可避過此劫全闷,所以路人甲就按照神秘高人Y指點(diǎn)秘密在全國(guó)各地建造一個(gè)物流據(jù)點(diǎn)叉寂,然后通過特制的千里箭進(jìn)行通訊)。
回到家中的路人甲里面把荔枝的貨物需求綁在千里箭中并射向了最近的據(jù)點(diǎn)bj倉(cāng)总珠,bj倉(cāng)的負(fù)責(zé)人收到之后屏鳍,發(fā)現(xiàn)這個(gè)倉(cāng)中沒有勘纯,然后又把這個(gè)需求通過千里箭射向了js倉(cāng),但最終在gd倉(cāng)找到了貨物钓瞭,再通過特制的飛鷂在三天內(nèi)把貨物送到楊貴妃所在的地方驳遵。
楊貴妃吃到了新鮮的荔枝之后,心情大悅山涡,路人甲也因此仕途暢通無阻超埋。
本故事終,故事純屬小Y瞎掰佳鳖,哇哈哈哈霍殴。
一、路人甲如何建立行之有效的物流系統(tǒng)
神秘高人Y把幾千年后的發(fā)達(dá)物流模式傳授給了路人甲系吩,要求在全國(guó)各大城市建立據(jù)點(diǎn)来庭。
1.粗糙期
①荔枝的接口
public interface ILiZhi {
//得到荔枝的品種
public int getType();
//每個(gè)倉(cāng)庫(kù)中得到荔枝訂單的請(qǐng)求
public String getRequest();
}
②定義荔枝的具體類
public class LiZhi implements ILiZhi {
//荔枝的種類,1代表糯米糍 2代表桂味 3代表槐味
private int type=0;
//荔枝的訂單需求
private String request;
public LiZhi(int type,String request) {
this.type = type;
this.request=request;
}
@Override
public int getType() {
return type;
}
@Override
public String getRequest() {
return request;
}
}
③定義一個(gè)據(jù)點(diǎn)接口
public interface ILiZhiHouse {
//處理訂單需求
public void dealWithRequest(ILiZhi iLiZhi);
}
④bj據(jù)點(diǎn)穿挨,只有糯米糍荔枝
public class BJHouse implements ILiZhiHouse {
@Override
public void dealWithRequest(ILiZhi iLiZhi) {
System.out.println("訂單需求:"+iLiZhi.getRequest());
System.out.println("貨物已由bj據(jù)點(diǎn)火速送出");
}
}
⑤js據(jù)點(diǎn)月弛,只有桂味荔枝
public class JSHouse implements ILiZhiHouse {
@Override
public void dealWithRequest(ILiZhi iLiZhi) {
System.out.println("訂單需求:"+iLiZhi.getRequest());
System.out.println("貨物已由js據(jù)點(diǎn)火速送出");
}
}
⑥gd據(jù)點(diǎn),只有槐味荔枝
public class GDHouse implements ILiZhiHouse {
@Override
public void dealWithRequest(ILiZhi iLiZhi) {
System.out.println("訂單需求:"+iLiZhi.getRequest());
System.out.println("貨物已由gd據(jù)點(diǎn)火速送出");
}
}
物流系統(tǒng)建好了科盛,現(xiàn)在就等楊貴妃下達(dá)荔枝需求了帽衙。
⑦楊貴妃一聲令下,要求三天之內(nèi)把糯米糍贞绵、桂味厉萝、槐味全部送達(dá)
public class Client {
public static void main(String[] args) {
//1代表糯米糍 2代表桂味 3代表槐味
//路人甲根據(jù)楊貴妃的要求組裝需求
List<ILiZhi> liZhis=new ArrayList<>();
liZhis.add(new LiZhi(1,"需要糯米糍30斤"));
liZhis.add(new LiZhi(2,"需要桂味30斤"));
liZhis.add(new LiZhi(3,"需要槐味30斤"));
//定義三個(gè)據(jù)點(diǎn)
BJHouse bjHouse=new BJHouse();
JSHouse jsHouse=new JSHouse();
GDHouse gdHouse=new GDHouse();
for(ILiZhi liZhi:liZhis){
if(liZhi.getType()==1){
bjHouse.dealWithRequest(liZhi);
}else if(liZhi.getType()==2){
jsHouse.dealWithRequest(liZhi);
}else if(liZhi.getType()==3){
gdHouse.dealWithRequest(liZhi);
}else{
System.out.println("沒有建立這樣的據(jù)點(diǎn),只能坐等死了榨崩。");
}
}
}
}
⑧運(yùn)行結(jié)果
訂單需求:需要糯米糍30斤
貨物已由bj據(jù)點(diǎn)火速送出
訂單需求:需要桂味30斤
貨物已由js據(jù)點(diǎn)火速送出
訂單需求:需要槐味30斤
貨物已由gd據(jù)點(diǎn)火速送出
這個(gè)就是早期路人甲根據(jù)神秘高人Y方法建立的一套物流系統(tǒng)谴垫,路人甲覺得這套系統(tǒng)已經(jīng)完美無缺了,但是給神秘高人Y一看母蛛,立馬指出了一下問題:
Client的代碼臃腫翩剪,不同的荔枝品種就需要增加一個(gè)判斷,隨著品種的增多會(huì)造成if...else的判斷越來越多彩郊,很容易出現(xiàn)混亂前弯,可讀性不強(qiáng)。
耦合過重秫逝,違背開閉原則恕出。
異常處理不合理。如果路人甲把糯米糍的訂單直接發(fā)到了配送桂味的據(jù)點(diǎn)筷登,那么桂味據(jù)點(diǎn)無法處理這個(gè)訂單呀剃根,不處理的話那么路人甲就要坐等死了。
路人甲一看分析出這么多問題前方,立馬根據(jù)需求設(shè)計(jì)了一個(gè)新的物流系統(tǒng):訂單下來狈醉,由近到遠(yuǎn)的據(jù)點(diǎn)一個(gè)個(gè)分配訂單廉油,比如說桂味訂單到了bj據(jù)點(diǎn),bj據(jù)點(diǎn)處理不了苗傅,只能把這個(gè)訂單繼續(xù)往下一個(gè)據(jù)點(diǎn)傳遞抒线,到達(dá)js據(jù)點(diǎn)能夠處理就進(jìn)行配送,不需要再外下一個(gè)據(jù)點(diǎn)進(jìn)行傳遞了渣慕,即必然有一個(gè)唯一的據(jù)點(diǎn)給出唯一的答復(fù)嘶炭。
2.完善期
(1)據(jù)點(diǎn)UML
(2)改進(jìn)后的物流系統(tǒng)代碼
①荔枝的接口
public interface ILiZhi {
//得到荔枝的品種
public int getType();
//每個(gè)倉(cāng)庫(kù)中得到荔枝訂單的請(qǐng)求
public String getRequest();
}
②定義荔枝的具體類
public class LiZhi implements ILiZhi {
//荔枝的種類,1代表糯米糍 2代表桂味 3代表槐味
private int type=0;
//荔枝的訂單需求
private String request;
public LiZhi(int type,String request) {
this.type = type;
this.request=request;
}
@Override
public int getType() {
return type;
}
@Override
public String getRequest() {
return request;
}
}
③定義一個(gè)抽象據(jù)點(diǎn)類
public abstract class ILiZhiHouse {
//定義三種類型
public final static int BJ_TYPE_REQUEST = 1;
public final static int JS_TYPE_REQUEST = 2;
public final static int GD_TYPE_REQUEST = 3;
//責(zé)任傳遞逊桦,下一個(gè)人責(zé)任人是誰
private ILiZhiHouse liZhiHouse;
//能處理的訂單
private int type =0;
public ILiZhiHouse(int type) {
this.type = type;
}
//分發(fā)請(qǐng)求
public void handleMessage(ILiZhi iLiZhi){
if(iLiZhi.getType()==type){
this.dealWithRequest(iLiZhi);
}else{
if(this.liZhiHouse!=null){
this.liZhiHouse.handleMessage(iLiZhi);
}else{
System.out.println("沒有建立這樣的據(jù)點(diǎn)眨猎,只能坐等死了。");
}
}
}
//設(shè)置下一個(gè)據(jù)點(diǎn)是哪個(gè)
public void setNext(ILiZhiHouse liZhiHouse){
this.liZhiHouse=liZhiHouse;
}
//處理訂單需求
public abstract void dealWithRequest(ILiZhi iLiZhi);
}
④bj據(jù)點(diǎn)强经,只有糯米糍荔枝
public class BJHouse extends ILiZhiHouse {
public BJHouse() {
super(BJ_TYPE_REQUEST);
}
@Override
public void dealWithRequest(ILiZhi iLiZhi) {
System.out.println("訂單需求:"+iLiZhi.getRequest());
System.out.println("貨物已由bj據(jù)點(diǎn)火速送出");
}
}
⑤js據(jù)點(diǎn)睡陪,只有桂味荔枝
public class JSHouse extends ILiZhiHouse {
public JSHouse() {
super(JS_TYPE_REQUEST);
}
@Override
public void dealWithRequest(ILiZhi iLiZhi) {
System.out.println("訂單需求:"+iLiZhi.getRequest());
System.out.println("獲取已由js據(jù)點(diǎn)火速送出");
}
}
⑥gd據(jù)點(diǎn),只有槐味荔枝
public class GDHouse extends ILiZhiHouse {
public GDHouse() {
super(GD_TYPE_REQUEST);
}
@Override
public void dealWithRequest(ILiZhi iLiZhi) {
System.out.println("訂單需求:"+iLiZhi.getRequest());
System.out.println("獲取已由gd據(jù)點(diǎn)火速送出");
}
}
⑦配送荔枝
public class Client {
public static void main(String[] args) {
//1代表糯米糍 2代表桂味 3代表槐味
//路人甲根據(jù)楊貴妃的要求組裝需求
List<ILiZhi> liZhis=new ArrayList<>();
liZhis.add(new LiZhi(ILiZhiHouse.BJ_TYPE_REQUEST,"需要糯米糍30斤"));
liZhis.add(new LiZhi(ILiZhiHouse.JS_TYPE_REQUEST,"需要桂味30斤"));
liZhis.add(new LiZhi(ILiZhiHouse.GD_TYPE_REQUEST,"需要槐味30斤"));
//定義三個(gè)據(jù)點(diǎn)
BJHouse bjHouse=new BJHouse();
JSHouse jsHouse=new JSHouse();
GDHouse gdHouse=new GDHouse();
//根據(jù)據(jù)點(diǎn)遠(yuǎn)近設(shè)定順序
bjHouse.setNext(jsHouse);
jsHouse.setNext(gdHouse);
for(ILiZhi liZhi:liZhis){
bjHouse.handleMessage(liZhi);
}
}
}
⑧運(yùn)行結(jié)果
訂單需求:需要糯米糍30斤
貨物已由bj據(jù)點(diǎn)火速送出
訂單需求:需要桂味30斤
貨物已由js據(jù)點(diǎn)火速送出
訂單需求:需要槐味30斤
貨物已由gd據(jù)點(diǎn)火速送出
業(yè)務(wù)調(diào)用類Client也不用去做判斷到底是需要誰去處理匿情,而且ILiZhiHouse抽象類的子類可以繼續(xù)增加下去兰迫,只需要擴(kuò)展傳遞鏈而已,調(diào)用類可以不用了解變化過程炬称,甚至是誰在處理這個(gè)請(qǐng)求都不用知道汁果。
二、基本概念
1.定義
使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求玲躯,從而避免了請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系据德。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求府蔗,直到有對(duì)象處理它為止晋控。
2.責(zé)任鏈的重點(diǎn)
責(zé)任鏈模式的重點(diǎn)是在“鏈”上,由一條鏈去處理相似的請(qǐng)求在鏈中決定誰來處理這個(gè)請(qǐng)求姓赤,并返回相應(yīng)的結(jié)果。
3.角色介紹
-
Handler
抽象的處理者實(shí)現(xiàn)三個(gè)職責(zé):一是定義一個(gè)請(qǐng)求的處理方法handleMessage仲吏;二是定義一個(gè)鏈的編排方法setNext不铆,設(shè)置下一個(gè)處理者;三是定義了具體的請(qǐng)求者必須實(shí)現(xiàn)的兩個(gè)方法:定義自己能夠處理的級(jí)別和具體的處理任務(wù)裹唆。
-
ConcreteHandler
責(zé)任鏈模式的核心在“鏈”上誓斥,“鏈”是由多個(gè)處理者ConcreteHandler組成的。具體的請(qǐng)求者必須實(shí)現(xiàn)的兩個(gè)方法:定義自己能夠處理的級(jí)別和具體的處理任務(wù)许帐。
三劳坑、責(zé)任鏈模式優(yōu)缺點(diǎn)
1.優(yōu)點(diǎn)
- 責(zé)任鏈模式非常顯著的優(yōu)點(diǎn)是將請(qǐng)求和處理分開。請(qǐng)求者可以不用知道是誰處理的成畦,處理者可以不用知道請(qǐng)求的全貌距芬,涝开,兩者解耦,提高系統(tǒng)的靈活性
2.缺點(diǎn)
性能問題框仔。每個(gè)請(qǐng)求都是從鏈頭遍歷到鏈尾舀武,特別是在鏈比較長(zhǎng)的時(shí)候,性能是一個(gè)非常大的問題
調(diào)試不很方便离斩,特別是鏈條比較長(zhǎng)银舱,環(huán)節(jié)比較多的時(shí)候,由于采用了類似遞歸的方式跛梗,調(diào)試的時(shí)候邏輯可能比較復(fù)雜寻馏。
四、總結(jié)
鏈中節(jié)點(diǎn)數(shù)量需要控制核偿,避免出現(xiàn)超長(zhǎng)鏈的情況诚欠,一般的做法是在Handler中設(shè)置一個(gè)最大節(jié)點(diǎn)數(shù)量,在setNext方法中判斷是否已經(jīng)是超過其閾值宪祥,超過則不允許該鏈建立聂薪,避免無意識(shí)地破壞系統(tǒng)性能。