Java學習筆記之--------責任鏈模式

責任鏈模式

將能夠處理同一類請求的對象連成一條鏈,所提交的請求沿着鏈傳遞,鏈上的對象逐個判斷是否有能力處理該請求,如果能則處理,如果不能則傳遞給鏈上的下一個對象。

場景

打牌時,輪流出牌;接力賽跑;大學中,獎學金審批;公司中,公文審批。

常見的公司內的請假審批流程:如果請假天數小於3天,主任審批;如果請假天數大於等於3天,小於10天,經理審批;如果大於等於10天,小於30天,總經理審批;如果大於等於30天,則自動拒絕。

責任鏈模式demo

實現這樣一個審批,SCM(Supply Chain Management 供應鏈管理)系統中,採購審批子系統的設計:

        採購金額小於5萬,主任審批;

        採購金額大於等於5萬,小於20萬,經理審批;

        採購金額大於等於20萬,總經理審批。

新建PurchaseRequest類封裝採購申請的基本信息(申請人姓名,申請金額,用途);新建一個抽象類Leader,然後主任類Director,經理類Manager,總經理類GeneralManager,代碼如下所示。

public class PurchaseRequest {
	//申請人姓名
	private  String empName;
	//申請金額
	private BigDecimal amount;
	//申請原因(用途)
	private String reason;
	public PurchaseRequest(String empName, BigDecimal amount, String reason) {
		this.empName = empName;
		this.amount = amount;
		this.reason = reason;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public BigDecimal getAmount() {
		return amount;
	}
	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}
	public String getReason() {
		return reason;
	}
	public void setReason(String reason) {
		this.reason = reason;
	}
}
public abstract class Leader {
	protected String name;
	//責任鏈上的後繼對象
	protected Leader nextLeader;

	public Leader(String name) {
		this.name = name;
	}
	//設定責任鏈上的後繼對象
	public void setNextLeader(Leader nextLeader) {
		this.nextLeader = nextLeader;
	}
	//處理請求的核心的業務方法
	public abstract void handleRequest(PurchaseRequest request);
}
public class Director extends Leader{
	public Director(String name) {
		super(name);
	}
	@Override
	public void handleRequest(PurchaseRequest request) {
		if (request.getAmount().compareTo(new BigDecimal(50000)) == -1){
			System.out.println("員工:" + request.getEmpName() +
					"申請,採購金額" + request.getAmount() +
					",原因(用途):" + request.getReason());
			System.out.println("主任:" + this.name + ",審批通過!");
		} else {
			if (nextLeader != null){
				this.nextLeader.handleRequest(request);
			}
		}
	}
}
public class Manager extends Leader{
	public Manager(String name) {
		super(name);
	}
	@Override
	public void handleRequest(PurchaseRequest request) {
		if (request.getAmount().compareTo(new BigDecimal(50000)) > -1 &&
				request.getAmount().compareTo(new BigDecimal(200000)) == -1){
			System.out.println("員工:" + request.getEmpName() +
					"申請,採購金額" + request.getAmount() +
					",原因(用途):" + request.getReason());
			System.out.println("經理:" + this.name + ",審批通過!");
		} else {
			if (nextLeader != null){
				this.nextLeader.handleRequest(request);
			}
		}
	}
}
public class GeneralManager extends Leader{
	public GeneralManager(String name) {
		super(name);
	}
	@Override
	public void handleRequest(PurchaseRequest request) {
		if (request.getAmount().compareTo(new BigDecimal(200000)) < 1){
			System.out.println("員工:" + request.getEmpName() +
					"申請,採購金額" + request.getAmount() +
					",原因(用途):" + request.getReason());
			System.out.println("總經理:" + this.name + ",審批通過!");
		} else {
			System.out.println("採購金額太大,請分批申請!");
		}
	}
}
public class Client {
	public static void main(String[] args) {
		Leader a = new Director("張主任");
		Leader b = new Manager("李經理");
		Leader c = new GeneralManager("趙總");
		//組織責任鏈對象的關係
		a.setNextLeader(b);
		b.setNextLeader(c);
		//開始採購金額審批
		PurchaseRequest request = new PurchaseRequest("小明", new BigDecimal(6000),"採購年會禮品!");
		a.handleRequest(request);
	}
}

當申請金額爲6000時,結果如圖所示:

如果將金額修改爲15萬,則運行結果爲:

如果公司設置了一個副總經理的職位,然後修改審批流程爲:

        採購金額小於5萬,主任審批;

        採購金額大於等於5萬,小於10萬,經理審批;

        採購金額大於等於10萬,小於20萬,副總經理審批;

        採購金額大於等於20萬,總經理審批。

只需要新增一個副總經理的類,然後將經理類Manager的審批金額上限修改爲10萬:

public class ViceGeneralManager extends Leader{
	public ViceGeneralManager(String name) {
		super(name);
	}
	@Override
	public void handleRequest(PurchaseRequest request) {
		if (request.getAmount().compareTo(new BigDecimal(100000)) > -1 &&
				request.getAmount().compareTo(new BigDecimal(200000)) == -1){
			System.out.println("員工:" + request.getEmpName() +
					"申請,採購金額" + request.getAmount() +
					",原因(用途):" + request.getReason());
			System.out.println("副總經理:" + this.name + ",審批通過!");
		} else {
			if (nextLeader != null){
				this.nextLeader.handleRequest(request);
			}
		}
	}
}
public class Client {
	public static void main(String[] args) {
		Leader a = new Director("張主任");
		Leader b = new Manager("李經理");
		Leader c = new ViceGeneralManager("孫副總");
		Leader d = new GeneralManager("趙總");
		//組織責任鏈對象的關係
		a.setNextLeader(b);
		b.setNextLeader(c);
		c.setNextLeader(d);
		//開始採購金額審批
		PurchaseRequest request = new PurchaseRequest("小明", new BigDecimal(150000),"採購年會禮品!");
		a.handleRequest(request);
	}
}

則運行結果爲:

可以看到,當申請金額爲15萬時,原來由經理審批,現在由副總經理審批,符合需求。

由於責任鏈的創建完全在客戶端,因此新增新的具體處理類對原有類庫沒有任何影響,只需要添加新類,然後在客戶端調用時添加即可。符合開閉原則。

類圖

idea自動生成的類圖如下所示:

非鏈表方式實現責任鏈

以上爲鏈表方式定義職責鏈的demo。還可以用非鏈表方式實現職責鏈。

通過集合、數組生成責任鏈模式更加實用。實際上,很多項目中,每個具體的handler並不是由開發團隊定義的,而是項目上線後由外部單位追加的,所以使用鏈表方式定義COR鏈就很困難。

開發中常見的場景

Java中,異常機制就是一種責任鏈模式。一個try可以對應多個catch,當第一個catch不匹配類型,則自動跳到第二個catch。

Javascript語言中,事件的冒泡和捕獲機制。Java語言中,事件的處理採用觀察者模式。

Servlet開發中,過濾器的鏈式處理。

Struts2中,攔截器的調用也是典型的責任鏈模式。

 

以上爲責任鏈模式的學習筆記,此文章爲尚學堂視頻的學習筆記+自己總結。

發佈了91 篇原創文章 · 獲贊 31 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章