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

詳解對象池模式 & 解釋器模式

開發(fā) 前端
設(shè)計模式系列文章之前已經(jīng)跟大家聊了一大半了,但是都是聊一些比較常見的設(shè)計模式,接下來我們主要是聊一些不常見的設(shè)計模式。

[[409809]]

設(shè)計模式系列文章之前已經(jīng)跟大家聊了一大半了,但是都是聊一些比較常見的設(shè)計模式,接下來我們主要是聊一些不常見的設(shè)計模式。

不常見的設(shè)計模式不意味則就可以不用了解,不用知道。

每一種設(shè)計模式都是為了處理一種業(yè)務(wù)場景,或者解決某種問題而存在的,還是那句話,存在即合理。

學(xué)習(xí)設(shè)計模式優(yōu)點:

  • 提升查看框架源碼的能力
  • 提升自己對復(fù)雜業(yè)務(wù)的邏輯的代碼設(shè)計能力以及code能力
  • 對面試以及后面的職場道路打下扎實的基礎(chǔ)

大綱 

對象池模式

在面試的時候,經(jīng)常會有一些面試官會問一些針對線上一些機器出現(xiàn)OOM 時應(yīng)該怎么去排查

現(xiàn)在比較常見的是第一種查看機器是否配置了自動生成Dump文件

查看方法一般則是進入機器的:/home/www/XXXXX(項目名)/bin 目錄下會有一個 setenv.sh 文件

cat一下文件觀察是否配置:

  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath=/tmp/heapdump.hprof

第二種就是自己offline出問題的機器自己dump一下文件。

然后開始用一些分析文件工具比如(MAT)等查看問題

頻繁的實例化對象,是很耗費資源的,同時也會頻繁的觸發(fā)GC操作,所以在處理一些封裝外部資源的對象時就應(yīng)該合理的去規(guī)避這一點。

解決方案這就是重用和共享這些創(chuàng)建成本高昂的對象,這就是對象池模式,也理解為池化技術(shù)。

結(jié)構(gòu)圖如下:

  • ResourcePool(資源池類):用于封裝邏輯的類,即用來保存和管理資源列表
  • Resource(資源類):用于封裝特定的資源類,資源類被資源池類飲用,所以只要資源池沒有被重新分配,所以它們就永遠不會被回收。
  • Client(請求客戶端):使用資源的類

以上結(jié)構(gòu)定義來之設(shè)計模式之美

通過結(jié)構(gòu)圖其實可以理解為,事先在機器內(nèi)存中開辟一塊內(nèi)存,用來事先存儲需要定義好的對象,當有需要的時候從內(nèi)存獲取一個,不用了之后再返回回去,來實現(xiàn)的一個池化技術(shù)。

對象池模式舉例

假設(shè)現(xiàn)在朋友A想買車了,但是現(xiàn)在又沒有那么多錢,只能找同學(xué)B借錢同時承諾只要兩個月后就會還錢。

同學(xué)B的存款是固定的,假設(shè)這就是資源池,那么朋友A就是請求客戶端了。那么代碼的實現(xiàn)就如下所示:

  1. public class Money { 
  2.     // 狀態(tài)是否是被借出去 
  3.     private Integer status; 
  4.     // 金額單位 W 
  5.     private Integer money; 
  6.  
  7.     public Integer getStatus() { 
  8.         return status; 
  9.     } 
  10.     public void setStatus(Integer status) { 
  11.         this.status = status; 
  12.     } 
  13.     public Integer getMoney() { 
  14.         return money; 
  15.     } 
  16.     public void setMoney(Integer money) { 
  17.         this.money = money; 
  18.     } 

定義一個資源類(money),里面有一個狀態(tài)標志當前對象是否是被占用,這個是重點

  1. public class ClassmateBPool { 
  2.  
  3.     // 對象池大小 可以理解為理想情況下自己最多可以借2W 
  4.     public static int numObjects = 2; 
  5.     // 對象池最大大小 可以理解為自己全部家當最多可以借出去錢 
  6.     public static int maxObjects = 5; 
  7.     // 存放對象池中對象的向量(Money) 
  8.     protected Vector<Money> objectsPool = null
  9.  
  10.     public ClassmateBPool() { 
  11.     } 
  12.  
  13.     /** 
  14.      * 初始化對象池 
  15.      */ 
  16.     public synchronized void createPool() { 
  17.         // 確保對象池沒有創(chuàng)建。如果創(chuàng)建了,保存對象 objectsPool 不會為空 
  18.         if (objectsPool != null) { 
  19.             System.out.println("對象池已經(jīng)創(chuàng)建"); 
  20.             return
  21.         } 
  22.         // 創(chuàng)建對象池,添加資源 
  23.         objectsPool = new Vector<Money>(); 
  24.         for (int i = 0; i < numObjects; i++) { 
  25.             objectsPool.add(create()); 
  26.         } 
  27.         System.out.println("對象池開始創(chuàng)建"); 
  28.     } 
  29.  
  30.  
  31.     public synchronized Money getMoney() { 
  32.         int times = 1; 
  33.         // 基本判斷 
  34.         if (objectsPool == null) { 
  35.             throw new RuntimeException("未創(chuàng)建對象池"); 
  36.         } 
  37.         Money money = null
  38.         // 獲得一個可用的對象 
  39.         money = getFreeMoney(); 
  40.  
  41.         // money==null ,證明當前沒有可以借出去的錢了,則開始從另外的銀行卡轉(zhuǎn)錢過來 
  42.         while (money == null) { 
  43.             // 開始擴充對象池 
  44.             createNewMoney(2); 
  45.  
  46.             // 擴充完了之后再去獲取空閑的金額 
  47.             money = getFreeMoney(); 
  48.             if (money != null) { 
  49.                 break; 
  50.             } 
  51.             // 重試次數(shù) 
  52.             times++; 
  53.             System.out.println("重試次數(shù):"+times); 
  54.             if (times > 3) { 
  55.                 throw new RuntimeException("當前沒有空閑的金額"); 
  56.             } 
  57.  
  58.         } 
  59.         System.out.println("借錢"+ JSON.toJSONString(money)); 
  60.         // 返回獲得的可用的對象 
  61.         return money; 
  62.     } 
  63.  
  64.  
  65.     /** 
  66.      * 返回金額 
  67.      */ 
  68.     public void returnMoney(Money money) { 
  69.         // 確保對象池存在,如果對象沒有創(chuàng)建(不存在),直接返回 
  70.         if (objectsPool == null) { 
  71.             return
  72.         } 
  73.         Iterator<Money> iterator = objectsPool.iterator(); 
  74.         while (iterator.hasNext()) { 
  75.             Money returnMoney = iterator.next(); 
  76.             if (money == returnMoney) { 
  77.                 money.setStatus(0); 
  78.                 System.out.println("還錢成功"); 
  79.                 break; 
  80.             } 
  81.  
  82.         } 
  83.     } 
  84.  
  85.    /**  
  86.     *擴充資源池 
  87.     */ 
  88.     public void createNewMoney(int increment) { 
  89.         for (int i = 0; i < increment; i++) { 
  90.             if (objectsPool.size() > maxObjects) { 
  91.                 return
  92.             } 
  93.             objectsPool.add(create()); 
  94.         } 
  95.     } 
  96.    
  97.   /** 
  98.     *查詢空閑金額 
  99.     */ 
  100.     private Money getFreeMoney() { 
  101.         Iterator<Money> iterator = objectsPool.iterator(); 
  102.         while (iterator.hasNext()) { 
  103.             Money money = iterator.next(); 
  104.             // 判斷是否是被占用 
  105.             if (money.getStatus() == 0) { 
  106.                 money.setStatus(1); 
  107.                 return money; 
  108.             } 
  109.         } 
  110.         return null
  111.     } 
  112.  
  113.     public Money create() { 
  114.         Money money = new Money(); 
  115.         money.setMoney(1); 
  116.         // 0 未被占用,1 占用 
  117.         money.setStatus(0); 
  118.         return money; 
  119.     } 

創(chuàng)建資源池類,里面包含了 初始化資源池方法createPool,以及獲取空閑金額getMoney方法,以及returnMoney歸還金額方法。

  1. public class ClientTest { 
  2.     public static void main(String[] args) { 
  3.  
  4.         ClassmateBPool classmateBPool = new ClassmateBPool(); 
  5.         // 初始化連接池 
  6.         classmateBPool.createPool(); 
  7.         // 借錢 
  8.         Money money = classmateBPool.getMoney(); 
  9.         //還錢 
  10.         classmateBPool.returnMoney(money); 
  11.         // result:對象池開始創(chuàng)建 
  12.         //        借錢{"money":1,"status":1} 
  13.         //        還錢成功 
  14.  
  15.         // 模擬10的請求 
  16.         for (int i = 0; i < 10; i++) { 
  17.             Money money1 = classmateBPool.getMoney(); 
  18.         } 
  19.         //result: 
  20.         //對象池開始創(chuàng)建 
  21.         //借錢{"money":1,"status":1} 
  22.         //借錢{"money":1,"status":1} 
  23.         //借錢{"money":1,"status":1} 
  24.         //借錢{"money":1,"status":1} 
  25.         //借錢{"money":1,"status":1} 
  26.         //借錢{"money":1,"status":1} 
  27.         //重試次數(shù):2 
  28.         //重試次數(shù):3 
  29.         //重試次數(shù):4 
  30.         //Exception in thread "main" java.lang.RuntimeException:當前沒有空閑的金額 
  31.        
  32.         // 模擬10的請求,同時在第3次第4次的是時候還錢了 
  33.         for (int i = 0; i < 10; i++) { 
  34.             Money money1 = classmateBPool.getMoney(); 
  35.             if (i == 3 || i == 4) { 
  36.                 classmateBPool.returnMoney(money1); 
  37.             } 
  38.         } 
  39.         //result: 
  40.         // 對象池開始創(chuàng)建 
  41.         //借錢{"money":1,"status":1} 
  42.         //借錢{"money":1,"status":1} 
  43.         //借錢{"money":1,"status":1} 
  44.         //借錢{"money":1,"status":1} 
  45.         //還錢成功 
  46.         //借錢{"money":1,"status":1} 
  47.         //還錢成功 
  48.         //借錢{"money":1,"status":1} 
  49.         //借錢{"money":1,"status":1} 
  50.         //借錢{"money":1,"status":1} 
  51.         //重試次數(shù):2 
  52.         //重試次數(shù):3 
  53.         //重試次數(shù):4 
  54.         //Exception in thread "main" java.lang.RuntimeException:當前沒有空閑的金額 
  55.     } 

最后就是測試demo了,分別用了一次請求,10次請求,以及有歸還的場景下。

以上就是對象池模式定義以及舉例代碼實現(xiàn)

針對這種池化技術(shù)比較常見于C3P0、DBCP、Proxool等連接池,但是也有一個通用的工具common-pool包里面的感興趣的同學(xué)可以通過這個demo之后再去看下源碼,對比一下自己是否理解對象池模式。

  • 對象池模式的優(yōu)點:
  • 能夠重復(fù)使用對象池的對象,較少了對象的創(chuàng)建,回收以及內(nèi)存等消耗。
  • 缺點:
  • 需要額外的開辟內(nèi)存空間,而且這個內(nèi)存大小,以及對象數(shù)量不好把控等。

小結(jié)

針對Java當前對象的分配操作也不是很慢了,而且這種業(yè)務(wù)場景我也基本沒有遇到所以沒辦法給大家找到合適的業(yè)務(wù)代碼舉例。

大家可以作為了解的形式去理解一下,方便我們?nèi)タ匆恍┰创a或者一些業(yè)務(wù)場景提供一定的思考。

下面給大家分享第二種不出常見的模式解釋器模式

解釋器模式

大家在寫正則表達式的時候不知道有沒有思考過一個問題,Java它是怎么解析我們寫的這個表達式語法呢?

不清的同學(xué)就看看這接下來的解釋器模式

解釋器模式定義:

  • GOF中的定義:解釋器模式為某個語言定義它的語法(或者叫文法)表示,并定義一個解釋器用來處理這個語法。

說白了就是定義一種規(guī)則,通過這種規(guī)則去解析按照這種規(guī)則編寫的句子。

有點繞?還是看下結(jié)構(gòu)圖吧:

 

  • Context(環(huán)境):用于封裝全局信息,所有具體的解釋器都是訪問Context
  • AbstraceExpression(抽象表達式):抽象接口類,聲明解釋器的具體方法
  • TerminalExpression(終結(jié)符表達式):一種解釋器類,實現(xiàn)與語法的終結(jié)符相關(guān)操作。
  • NonTerminalExpression(非終結(jié)符表達式):實現(xiàn)語法的不同規(guī)則或符號的類。每一種語法都對應(yīng)著一個這種類
  • 以上結(jié)構(gòu)圖定義來之設(shè)計模式之美

舉例

看上面的結(jié)構(gòu)圖以及定義我估計很多同學(xué)還是沒有理解,那我們還是來個實際一點的例子好了

假設(shè)現(xiàn)在要我們實現(xiàn)小學(xué)數(shù)學(xué)里面的加減乘除運算,輸入任意的表達式能準確的得到結(jié)果

比如:(6➕6)✖️3 或者 2✖️3➕6

當然上面這種列子我們直接輸入肯定是不能實現(xiàn)的,得按照需要的語法規(guī)則才行所以:

  • (6➕6)✖️3 輸入的語法可以理解為 6 6 ➕ 3 ✖️
  • 2✖️3➕6 輸入的語法可以理解為 2 3 ✖️ 6 ➕

以(6➕6)✖️3為例整個運算過程,如圖所示

話不多說,直接開始擼代碼了。

  1. // 定義抽象表達式 
  2. public interface Expression { 
  3.     Long interpret(); 
  4.  
  5. // 乘法表達式 
  6. public class MultiplyExpression implements Expression { 
  7.     Expression left
  8.     Expression right
  9.     public MultiplyExpression(Expression left, Expression right) { 
  10.         this.left = left
  11.         this.right = right
  12.     } 
  13.  
  14.     @Override 
  15.     public Long interpret() { 
  16.         return left.interpret() * right.interpret(); 
  17.     } 
  18.  
  19. // 數(shù)字表達式 
  20. public class NumberExpression implements Expression { 
  21.     private Long number; 
  22.     public NumberExpression(Long number) { 
  23.         this.number = number; 
  24.     } 
  25.  
  26.     @Override 
  27.     public Long interpret() { 
  28.         return number; 
  29.     } 

上面很簡單就是定義一個抽象表達式接口,聲明解釋器的具體方法interpret,同時定義不同的語法NonTerminalExpression

  1. public class Context { 
  2.  
  3.     private Deque<Expression> numbers = new LinkedList<>(); 
  4.  
  5.     public Long ExpressionInterpreter(String expression) { 
  6.         Long result = null
  7.         for (String ex : expression.split(" ")) { 
  8.             if (isOperator(ex)) { 
  9.                 Expression exp = null
  10.                 if (ex.equals("+")) { 
  11.                     exp = new AddExpression(numbers.pollFirst(), numbers.pollFirst()); 
  12.                 } 
  13.                 if (ex.equals("*")) { 
  14.                     exp = new MultiplyExpression(numbers.pollFirst(), numbers.pollFirst()); 
  15.                 } 
  16.                 // 當還有其他的運算符時,接著在這里添加就行了 
  17.  
  18.                 if (null != exp) { 
  19.                     result = exp.interpret(); 
  20.                     numbers.addFirst(new NumberExpression(result)); 
  21.                 } 
  22.             } 
  23.             if (isNumber(ex)) { 
  24.                 numbers.addLast(new NumberExpression(Long.parseLong(ex))); 
  25.             } 
  26.         } 
  27.         return result; 
  28.     } 
  29.  
  30.     // 判斷是否是運算符號,這里舉例只用了➕和✖️,可以擴展更多的其它運算符 
  31.     private boolean isOperator(String ex) { 
  32.         return ex.equals("+") || ex.equals("*"); 
  33.     } 
  34.  
  35.     // 判斷是否是數(shù)字 
  36.     private boolean isNumber(String ex) { 
  37.         return ex.chars().allMatch(Character::isDigit); 
  38.     } 

定義環(huán)境具體的運算規(guī)則,需要注意的是后續(xù)如果有更多的運算符號只需接著在后面添加就可以了。

這我們是用的Deque作為整個運算的順序鏈表,可以用其他的方式比如Stack等。

  1. public class ExpressionPatternDemo { 
  2.     public static void main(String[] args) { 
  3.         Context context = new Context(); 
  4.         Long result = context.ExpressionInterpreter("6 6 + 3 *"); 
  5.         System.out.println(result); 
  6.         // result : 36 
  7.         Context contextTwo = new Context(); 
  8.         Long resultTwo = contextTwo.ExpressionInterpreter("2 3 * 6 +"); 
  9.         System.out.println(resultTwo); 
  10.         // result : 12 
  11.     } 

最后就是來看我們的測試demo了。

按照我們輸入的語法規(guī)則,解釋出我們想要的結(jié)果,這就是解釋器模式。

因為解釋器模式我們本身接觸很少,大家作為一個了解就可以了,更多的是運用在表達式,或者規(guī)則引擎等地方。

感興趣的伙伴可以再去看看Pattern.compile的源碼,本質(zhì)也是用的解釋器模式

總結(jié)

針對這些不怎么常見,或者在業(yè)務(wù)代碼中不怎么常見的模式只能是跟大家分享一下它的原理以及應(yīng)用場景,大家可以作為了解的形式來理解它,方便在以后遇到的問題,能有一個好的思路。

學(xué)習(xí)的越多,了解的越多對我們本身是沒有壞處的。

本次的分享到這里就結(jié)束了,我是敖丙,你知道的越多,你不知道的越多,我們下期見!

 

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

2020-11-09 08:20:33

解釋器模式

2023-05-15 08:51:46

解釋器模式定義

2010-04-21 08:38:18

解釋器模式PHP設(shè)計模式

2021-11-29 09:38:12

設(shè)計模式對象池模式Object Pool

2024-06-05 09:41:41

2023-03-03 08:12:07

設(shè)計模式語言

2021-06-29 08:54:23

設(shè)計模式代理模式遠程代理

2023-03-08 08:12:18

對象池模式設(shè)計模式

2013-05-23 15:59:00

線程池

2013-01-11 09:40:56

設(shè)計模式.NET

2021-11-28 22:33:01

Go選項模式

2011-06-28 15:01:01

Qt PIMPL

2023-09-04 13:14:00

裝飾器設(shè)計模式

2021-10-30 20:49:24

算法 Xpath路徑

2010-06-29 14:33:36

UML面向?qū)ο蠼?/a>

2024-12-24 11:01:58

2010-01-21 09:08:53

.NET設(shè)計模式

2023-12-13 13:28:16

裝飾器模式Python設(shè)計模式

2021-06-22 15:27:13

設(shè)計模式迭代器模式Java

2022-10-13 08:08:40

解釋器模式算法
點贊
收藏

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