自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

阿丙華為面試:什么是責(zé)任鏈模式?

開發(fā) 前端
設(shè)計模式不是一成不變的,只有適合自己當(dāng)前業(yè)務(wù)的模式才是最好的模式。理解前輩的思想,組合我們自己需要的模式。

[[401366]]

前言

面試經(jīng)歷大家肯定都有過,但是面試的流程其實跟一種設(shè)計模式很像,每一輪的面試官都有自己的職責(zé),一個求職者面試經(jīng)歷的過程就好比一次客戶端的請求過程。

在設(shè)計模式系列的文章中之前已經(jīng)為大家分享了創(chuàng)建型設(shè)計模式,感興趣的小伙伴們可以再去翻看之前的分享。接下來開始分享設(shè)計模式三大類型中的行為型模式了,今天要分享的是責(zé)任鏈模式

大綱

定義

什么是責(zé)任鏈?它的原理是什么?

  • 將請求的發(fā)送和接收解耦,讓多個接收對象都有機會處理這個請求。將這些接收對象串成一條鏈,并沿著這條鏈傳遞這個請求,直到鏈上的某個接收對象能夠處理它為止。
  • 以上定義來自《設(shè)計模式之美》

再看看一張官方圖解吧

  • Client(客戶端):實例化一個處理器的鏈,在第一個鏈對象中調(diào)用handleRequest 方法。
  • Handle(處理器):抽象類,提供給實際處理器繼承然后實現(xiàn)handleRequst方法,處理請求
  • ConcreteHandler(具體處理器):繼承了handler的類,同時實現(xiàn)handleRequst方法,負(fù)責(zé)處理業(yè)務(wù)邏輯類,不同業(yè)務(wù)模塊有不同的ConcreteHandler。

這么看結(jié)構(gòu)其實還是比較簡單的,但是我們還是拿面試的流程來模擬一下責(zé)任鏈吧!

代碼實現(xiàn)

假設(shè)現(xiàn)在去一家公司面試,第一次去一面,第二次去二面,第三次去直接過了。那這個模擬面試代碼怎么寫呢?

  1. public abstract class Handler { 
  2.  
  3.     protected Handler handler; 
  4.  
  5.     public void setHandler(Handler handler) { 
  6.         this.handler = handler; 
  7.     } 
  8.     public abstract void handleRequest(Integer times); 

首先我們還是定義一個抽象Handler處理器,同時添加一個抽象處理方法 handleRequest,后面我只需要編寫具體的處理器來繼承Handler類

  1. public class FirstInterview extends Handler { 
  2.     @Override 
  3.     public void handleRequest(Integer times) { 
  4.         // 條件判斷是否是屬于當(dāng)前Handler的處理范圍之內(nèi),不是則向下傳遞Handler處理器 
  5.         if(times ==1){ 
  6.           // 假設(shè)這里是處理的業(yè)務(wù)邏輯代碼 
  7.             System.out.println("第一次面試"+times); 
  8.         } 
  9.         handler.handleRequest(times); 
  10.     } 

其次構(gòu)建第一次面試Handler,內(nèi)部實現(xiàn)handleRequest方法,判斷一下是否是當(dāng)前處理應(yīng)該處理的業(yè)務(wù)邏輯,不是則向下傳遞。同樣的第二次的SecondInterview和FirstInterview代碼基本是一致的,我就不給大家貼出來了,直接看最后一個

  1. public class ThreeInterview extends Handler { 
  2.     @Override 
  3.     public void handleRequest(Integer times) { 
  4.         if (times == 3) { 
  5.             System.out.println("第三次面試"+ times + ",恭喜面試通過,HR會跟你聯(lián)      系?。。?quot;); 
  6.         } 
  7.     } 
  8.  
  9.     public static void main(String[] args) { 
  10.         Handler first = new FirstInterview(); 
  11.         Handler second = new SecondInterview(); 
  12.         Handler three = new ThreeInterview(); 
  13.         first.setHandler(second); 
  14.         second.setHandler(three); 
  15.  
  16.         // 第一次面試 
  17.         first.handleRequest(1); 
  18.         System.out.println(); 
  19.         // 第二次面試 
  20.         first.handleRequest(2); 
  21.         System.out.println(); 
  22.         // 第三次面試 
  23.         first.handleRequest(3); 
  24.         System.out.println(); 
  25.     } 

 

這個結(jié)果可以很明顯的看出,根據(jù)我們傳參,不同的Handler根據(jù)自己的職責(zé)處理著自己的業(yè)務(wù),這就是責(zé)任鏈。

框架的應(yīng)用

責(zé)任鏈在很多框架源碼中也有體現(xiàn)。比如開始學(xué)SpringMVC中的 ServletFilter

以及Spring中的 SpringInterceptor 這里面其實都是運用了責(zé)任鏈模式的思想,達到框架的可擴展性的同時也遵循著開閉原則。

作為常見的RPC框架的DUBBO其實里面也同樣有這個責(zé)任鏈的思想。

給大家一個思考問題?

  • dubbo服務(wù)一旦暴露出去了,那么基本任何服務(wù)都能調(diào)用,但是在一些特殊的業(yè)務(wù)中需要我們暴露服務(wù),但是又不希望被不了解業(yè)務(wù)的人隨便調(diào)用。
  • 比如:商品的庫存修改的dubbo服務(wù),我們只允許下單,購物車,添加修改商品等一些指定場景可以調(diào)用。
  • 那么有什么辦法,在Provider這端做好攔截,針對特定的服務(wù)才允許調(diào)用,否則攔截下來不允許執(zhí)行?

第一種方法,添加服務(wù)名稱APP_NAME作為傳參校驗,這是很常見也最容易想到的辦法。

第二種方法,實現(xiàn)一個DUBBO攔截器,對RPC調(diào)用進行選擇性過濾。

針對上面的兩種方法,給大家詳細講講第二種方法具體怎么實現(xiàn),每個公司都會基于現(xiàn)有的DUBBO源碼做自己的特定化改動,那么第二種方式也是同樣需要我們改動線有dubbo源碼。

先修改ConsumerContextFilter消費者攔截器

這里我們以dubbo的2.7.19版本為例。在ConsumerContextFilter中添加APP_NAME至Attachments中,那么作為本次的RPC調(diào)用都能從Attachments中獲取到我們?nèi)氲闹怠?/p>

至于這個APP_NAME的獲取 可以通過 System.getProperty("project.name", "") 來獲取服務(wù)名

  • 這里我就不對DUBBO做過多的展開,大家如果有強烈建議講解。那么在結(jié)束設(shè)計模式再跟大家詳細剖析一下dubbo,以及zookeeper里面的ZAB,一致性選舉算法等等。

CONSUMER既然已經(jīng)填充了服務(wù)名稱,那么在Provider同樣的也就只需要寫一個ProviderFilter 就可以了

這里就基本實現(xiàn)怎么處理每一次RPC調(diào)用的攔截了,然后想要那個服務(wù)攔截,在provider里面的filter里面指定一下這個DubboProviderFilter就可以了,也可以全局都實現(xiàn)。

注意 :這個Filter 要是用DUBBO包里面的,不要搞錯了。

現(xiàn)實業(yè)務(wù)改造舉例

框架中既然都有這種思想,那么怎么運用到業(yè)務(wù)代碼中呢?

還是給大家舉一個例子:

商品詳情展示我們可以是分模塊展示的,比如頭圖,商品信息,sku信息,配送地址,分期付費等等。

那么怎么進行組裝到商品詳情的展示呢?

  1. public abstract class AbstractDataHandler<T> { 
  2.  
  3.     // 處理模塊化數(shù)據(jù) 
  4.     protected abstract T doRequest(String query) throws Exception; 

首先我們還是定一個抽象數(shù)據(jù)Handler,然后分別建立ItemInfoHandler 和SkuInfoHandler 來繼承抽象處理器

  1. @Component 
  2. public class ItemInfoHandler extends AbstractDataHandler<ItemInfoHandler.ItemInfo> { 
  3.     @Override 
  4.     protected ItemInfoHandler.ItemInfo doRequest(String query) { 
  5.         ItemInfoHandler.ItemInfo info = new ItemInfo(); 
  6.         info.setItemId(123456L); 
  7.         info.setItemName("測試商品"); 
  8.         return info; 
  9.     } 
  10.  
  11.     @Data 
  12.     public static class ItemInfo { 
  13.         private Long itemId; 
  14.         private String itemName; 
  15.     } 

同樣SkuInfoHandler類也是一樣的

  1. @Component 
  2. public class SkuInfoHandler extends AbstractDataHandler<SkuInfoHandler.SkuInfo> { 
  3.     @Override 
  4.     protected SkuInfoHandler.SkuInfo doRequest(String query) { 
  5.         SkuInfoHandler.SkuInfo info = new SkuInfoHandler.SkuInfo(); 
  6.         info.setSkuId(78910L); 
  7.         info.setSkuName("測試SKU"); 
  8.         return info; 
  9.     } 
  10.     @Data 
  11.     public static class SkuInfo { 
  12.         private Long skuId; 
  13.         private String skuName; 
  14.     } 

最后就是我們的測試代碼了

  1. @Component 
  2. public class DataAggregation { 
  3.     @Autowired 
  4.     private SkuInfoHandler skuInfoHandler; 
  5.     @Autowired 
  6.     private ItemInfoHandler itemInfoHandler; 
  7.  
  8.     public Map convertItemDetail() throws Exception { 
  9.        Map result = new HashMap(); 
  10.        result.put("skuInfoHandler", skuInfoHandler.doRequest("模擬數(shù)據(jù)請求")); 
  11.        result.put("itemInfoHandler",itemInfoHandler.doRequest("模擬數(shù)據(jù)請求")); 
  12.        return result; 
  13.     } 
  14.  
  15.     public static void main(String[] args) throws Exception { 
  16.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); 
  17.         DataAggregation dataAggregation = (DataAggregation) applicationContext.getBean("dataAggregation"); 
  18.         Map map = dataAggregation.convertItemDetail(); 
  19.         System.out.println(JSON.toJSONString(map)); 
  20.       // 打印的結(jié)果數(shù)據(jù) 
  21.       // {"skuInfoHandler":{"skuId":78910,"skuName":"測試SKU"},"itemInfoHandler":{"itemId":123456,"itemName":"測試商品"}} 
  22.     } 

這個例子其實是經(jīng)過一點小小的改動的,我們沒有通過向下傳遞處理器的方式,而是通過實際業(yè)務(wù)邏輯在 convertItemDetail 的方法中去構(gòu)建每個模塊的數(shù)據(jù),最后返回出一個Map結(jié)構(gòu)數(shù)據(jù)。

這里其實還有另外的一種寫法,把每一個需要處理的Handler 可以加載到一個List容器中,然后循環(huán)調(diào)用每個Handler中的doRequest方法,當(dāng)然這是針對一些其他的業(yè)務(wù)場景這么寫。

看完大家也能發(fā)現(xiàn)其實每個Handler是可以共用的,每一塊業(yè)務(wù)的代碼邏輯非常的清晰,這樣的代碼寫出來就感覺很舒服了。

總結(jié)

設(shè)計模式不是一成不變的,只有適合自己當(dāng)前業(yè)務(wù)的模式才是最好的模式。理解前輩的思想,組合我們自己需要的模式。

本次分享就到這里了,后面接著為大家分享行為型設(shè)計模式。

 

責(zé)任編輯:姜華 來源: 三太子敖丙
相關(guān)推薦

2024-12-03 15:52:45

責(zé)任鏈Java

2021-12-24 07:50:45

責(zé)任鏈模式設(shè)計

2022-12-28 08:08:57

2012-03-28 13:28:56

Java設(shè)計模式

2022-11-01 08:46:20

責(zé)任鏈模式對象

2010-04-01 09:10:03

PHP設(shè)計模式責(zé)任鏈模式

2021-07-14 10:08:30

責(zé)任鏈模式加工鏈

2024-01-30 13:15:00

設(shè)計模式責(zé)任鏈

2023-09-28 08:45:56

開源責(zé)任鏈模式

2021-06-05 17:59:00

責(zé)任鏈模式設(shè)計

2021-11-22 23:50:59

責(zé)任鏈模式場景

2024-06-04 13:11:52

Python行為設(shè)計模式開發(fā)

2022-07-04 15:40:11

數(shù)據(jù)供應(yīng)鏈數(shù)據(jù)分析

2022-07-05 11:40:42

大數(shù)據(jù)供應(yīng)鏈工具

2023-09-26 00:27:07

設(shè)計模式鏈接

2023-06-05 07:55:31

2024-05-09 12:17:00

責(zé)任鏈設(shè)計模式

2009-03-16 15:55:21

Java責(zé)任鏈模式

2025-01-03 10:32:26

Spring責(zé)任鏈模式

2020-11-17 09:32:57

設(shè)計模式責(zé)任鏈
點贊
收藏

51CTO技術(shù)棧公眾號