欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

快速了解Java中NIO核心組件

 更新時(shí)間:2017年12月14日 11:12:59   作者:default  
這篇文章主要介紹了快速了解Java中NIO核心組件,涉及相關(guān)介紹及完整實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。

背景知識(shí)

同步、異步、阻塞、非阻塞

首先,這幾個(gè)概念非常容易搞混淆,但NIO中又有涉及,所以總結(jié)一下。

同步:API調(diào)用返回時(shí)調(diào)用者就知道操作的結(jié)果如何了(實(shí)際讀取/寫(xiě)入了多少字節(jié))。

異步:相對(duì)于同步,API調(diào)用返回時(shí)調(diào)用者不知道操作的結(jié)果,后面才會(huì)回調(diào)通知結(jié)果。

阻塞:當(dāng)無(wú)數(shù)據(jù)可讀,或者不能寫(xiě)入所有數(shù)據(jù)時(shí),掛起當(dāng)前線程等待。

非阻塞:讀取時(shí),可以讀多少數(shù)據(jù)就讀多少然后返回,寫(xiě)入時(shí),可以寫(xiě)入多少數(shù)據(jù)就寫(xiě)入多少然后返回。

對(duì)于I/O操作,根據(jù)Oracle官網(wǎng)的文檔,同步異步的劃分標(biāo)準(zhǔn)是“調(diào)用者是否需要等待I/O操作完成”,這個(gè)“等待I/O操作完成”的意思不是指一定要讀取到數(shù)據(jù)或者說(shuō)寫(xiě)入所有數(shù)據(jù),而是指真正進(jìn)行I/O操作時(shí),比如數(shù)據(jù)在TCP/IP協(xié)議棧緩沖區(qū)和JVM緩沖區(qū)之間傳輸?shù)倪@段時(shí)間,調(diào)用者是否要等待。

所以,我們常用的read()和write()方法都是同步I/O,同步I/O又分為阻塞和非阻塞兩種模式,如果是非阻塞模式,檢測(cè)到無(wú)數(shù)據(jù)可讀時(shí),直接就返回了,并沒(méi)有真正執(zhí)行I/O操作。

總結(jié)就是,Java中實(shí)際上只有同步阻塞I/O、同步非阻塞I/O與異步I/O三種機(jī)制,我們下文所說(shuō)的是前兩種,JDK1.7才開(kāi)始引入異步I/O,那稱之為NIO.2。

傳統(tǒng)IO

我們知道,一個(gè)新技術(shù)的出現(xiàn)總是伴隨著改進(jìn)和提升,JavaNIO的出現(xiàn)亦如此。

傳統(tǒng)I/O是阻塞式I/O,主要問(wèn)題是系統(tǒng)資源的浪費(fèi)。比如我們?yōu)榱俗x取一個(gè)TCP連接的數(shù)據(jù),調(diào)用InputStream的read()方法,這會(huì)使當(dāng)前線程被掛起,直到有數(shù)據(jù)到達(dá)才被喚醒,那該線程在數(shù)據(jù)到達(dá)這段時(shí)間內(nèi),占用著內(nèi)存資源(存儲(chǔ)線程棧)卻無(wú)所作為,也就是俗話說(shuō)的占著茅坑不拉屎,為了讀取其他連接的數(shù)據(jù),我們不得不啟動(dòng)另外的線程。在并發(fā)連接數(shù)量不多的時(shí)候,這可能沒(méi)什么問(wèn)題,然而當(dāng)連接數(shù)量達(dá)到一定規(guī)模,內(nèi)存資源會(huì)被大量線程消耗殆盡。另一方面,線程切換需要更改處理器的狀態(tài),比如程序計(jì)數(shù)器、寄存器的值,因此非常頻繁的在大量線程之間切換,同樣是一種資源浪費(fèi)。

隨著技術(shù)的發(fā)展,現(xiàn)代操作系統(tǒng)提供了新的I/O機(jī)制,可以避免這種資源浪費(fèi)?;诖耍Q生了JavaNIO,NIO的代表性特征就是非阻塞I/O。緊接著我們發(fā)現(xiàn),簡(jiǎn)單的使用非阻塞I/O并不能解決問(wèn)題,因?yàn)樵诜亲枞J较?,read()方法在沒(méi)有讀取到數(shù)據(jù)時(shí)就會(huì)立即返回,不知道數(shù)據(jù)何時(shí)到達(dá)的我們,只能不停的調(diào)用read()方法進(jìn)行重試,這顯然太浪費(fèi)CPU資源了,從下文可以知道,Selector組件正是為解決此問(wèn)題而生。

JavaNIO核心組件

1.Channel

概念

JavaNIO中的所有I/O操作都基于Channel對(duì)象,就像流操作都要基于Stream對(duì)象一樣,因此很有必要先了解Channel是什么。以下內(nèi)容摘自JDK1.8的文檔

Achannelrepresentsanopenconnectiontoanentitysuchasahardwaredevice,afile,anetworksocket,oraprogramcomponentthatiscapableofperformingoneormoredistinctI/Ooperations,forexamplereadingorwriting.

從上述內(nèi)容可知,一個(gè)Channel(通道)代表和某一實(shí)體的連接,這個(gè)實(shí)體可以是文件、網(wǎng)絡(luò)套接字等。也就是說(shuō),通道是JavaNIO提供的一座橋梁,用于我們的程序和操作系統(tǒng)底層I/O服務(wù)進(jìn)行交互。

通道是一種很基本很抽象的描述,和不同的I/O服務(wù)交互,執(zhí)行不同的I/O操作,實(shí)現(xiàn)不一樣,因此具體的有FileChannel、SocketChannel等。

通道使用起來(lái)跟Stream比較像,可以讀取數(shù)據(jù)到Buffer中,也可以把Buffer中的數(shù)據(jù)寫(xiě)入通道。

當(dāng)然,也有區(qū)別,主要體現(xiàn)在如下兩點(diǎn):

一個(gè)通道,既可以讀又可以寫(xiě),而一個(gè)Stream是單向的(所以分InputStream和OutputStream)

通道有非阻塞I/O模式

實(shí)現(xiàn)

JavaNIO中最常用的通道實(shí)現(xiàn)是如下幾個(gè),可以看出跟傳統(tǒng)的I/O操作類(lèi)是一一對(duì)應(yīng)的。

FileChannel:讀寫(xiě)文件

DatagramChannel:UDP協(xié)議網(wǎng)絡(luò)通信

SocketChannel:TCP協(xié)議網(wǎng)絡(luò)通信

ServerSocketChannel:監(jiān)聽(tīng)TCP連接

2.Buffer

NIO中所使用的緩沖區(qū)不是一個(gè)簡(jiǎn)單的byte數(shù)組,而是封裝過(guò)的Buffer類(lèi),通過(guò)它提供的API,我們可以靈活的操縱數(shù)據(jù),下面細(xì)細(xì)道來(lái)。

與Java基本類(lèi)型相對(duì)應(yīng),NIO提供了多種Buffer類(lèi)型,如ByteBuffer、CharBuffer、IntBuffer等,區(qū)別就是讀寫(xiě)緩沖區(qū)時(shí)的單位長(zhǎng)度不一樣(以對(duì)應(yīng)類(lèi)型的變量為單位進(jìn)行讀寫(xiě))。

Buffer中有3個(gè)很重要的變量,它們是理解Buffer工作機(jī)制的關(guān)鍵,分別是

capacity(總?cè)萘浚?/p>

position(指針當(dāng)前位置)

limit(讀/寫(xiě)邊界位置)

Buffer的工作方式跟C語(yǔ)言里的字符數(shù)組非常的像,類(lèi)比一下,capacity就是數(shù)組的總長(zhǎng)度,position就是我們讀/寫(xiě)字符的下標(biāo)變量,limit就是結(jié)束符的位置。Buffer初始時(shí)3個(gè)變量的情況如下圖

在對(duì)Buffer進(jìn)行讀/寫(xiě)的過(guò)程中,position會(huì)往后移動(dòng),而limit就是position移動(dòng)的邊界。由此不難想象,在對(duì)Buffer進(jìn)行寫(xiě)入操作時(shí),limit應(yīng)當(dāng)設(shè)置為capacity的大小,而對(duì)Buffer進(jìn)行讀取操作時(shí),limit應(yīng)當(dāng)設(shè)置為數(shù)據(jù)的實(shí)際結(jié)束位置。(注意:將Buffer數(shù)據(jù)寫(xiě)入通道是Buffer讀取操作,從通道讀取數(shù)據(jù)到Buffer是Buffer寫(xiě)入操作)

在對(duì)Buffer進(jìn)行讀/寫(xiě)操作前,我們可以調(diào)用Buffer類(lèi)提供的一些輔助方法來(lái)正確設(shè)置position和limit的值,主要有如下幾個(gè)

flip():設(shè)置limit為position的值,然后position置為0。對(duì)Buffer進(jìn)行讀取操作前調(diào)用。

rewind():僅僅將position置0。一般是在重新讀取Buffer數(shù)據(jù)前調(diào)用,比如要讀取同一個(gè)Buffer的數(shù)據(jù)寫(xiě)入多個(gè)通道時(shí)會(huì)用到。

clear():回到初始狀態(tài),即limit等于capacity,position置0。重新對(duì)Buffer進(jìn)行寫(xiě)入操作前調(diào)用。

compact():將未讀取完的數(shù)據(jù)(position與limit之間的數(shù)據(jù))移動(dòng)到緩沖區(qū)開(kāi)頭,并將position設(shè)置為這段數(shù)據(jù)末尾的下一個(gè)位置。其實(shí)就等價(jià)于重新向緩沖區(qū)中寫(xiě)入了這么一段數(shù)據(jù)。

然后,看一個(gè)實(shí)例,使用FileChannel讀寫(xiě)文本文件,通過(guò)這個(gè)例子驗(yàn)證通道可讀可寫(xiě)的特性以及Buffer的基本用法(注意FileChannel不能設(shè)置為非阻塞模式)。

FileChannel channel = new RandomAccessFile("test.txt", "rw").getChannel();
channel.position(channel.size());
// 移動(dòng)文件指針到末尾(追加寫(xiě)入)
ByteBuffer byteBuffer = ByteBuffer.allocate(20);
// 數(shù)據(jù)寫(xiě)入Buffer
byteBuffer.put("你好,世界!\n".getBytes(StandardCharsets.UTF_8));
// Buffer -> Channel
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
	channel.write(byteBuffer);
}
channel.position(0);
// 移動(dòng)文件指針到開(kāi)頭(從頭讀?。?
CharBuffer charBuffer = CharBuffer.allocate(10);
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
// 讀出所有數(shù)據(jù)
byteBuffer.clear();
while (channel.read(byteBuffer) != -1 || byteBuffer.position() > 0) {
	byteBuffer.flip();
	// 使用UTF-8解碼器解碼
	charBuffer.clear();
	decoder.decode(byteBuffer, charBuffer, false);
	System.out.print(charBuffer.flip().toString());
	byteBuffer.compact();
	// 數(shù)據(jù)可能有剩余
}
channel.close();

這個(gè)例子中使用了兩個(gè)Buffer,其中 byteBuffer 作為通道讀寫(xiě)的數(shù)據(jù)緩沖區(qū),charBuffer 用于存儲(chǔ)解碼后的字符。clear() 和 flip() 的用法正如上文所述,需要注意的是最后那個(gè) compact() 方法,即使 charBuffer 的大小完全足以容納 byteBuffer 解碼后的數(shù)據(jù),這個(gè) compact() 也必不可少,這是因?yàn)槌S弥形淖址腢TF-8編碼占3個(gè)字節(jié),因此有很大概率出現(xiàn)在中間截?cái)嗟那闆r,請(qǐng)看下圖:

當(dāng) Decoder 讀取到緩沖區(qū)末尾的 0xe4 時(shí),無(wú)法將其映射到一個(gè) Unicode,decode()方法第三個(gè)參數(shù) false 的作用就是讓 Decoder 把無(wú)法映射的字節(jié)及其后面的數(shù)據(jù)都視作附加數(shù)據(jù),因此 decode() 方法會(huì)在此處停止,并且 position 會(huì)回退到 0xe4 的位置。如此一來(lái), 緩沖區(qū)中就遺留了“中”字編碼的第一個(gè)字節(jié),必須將其 compact 到前面,以正確的和后序數(shù)據(jù)拼接起來(lái)。關(guān)于字符編碼,大家可以參閱ANSI,Unicode,BMP,UTF等編碼概念實(shí)例講解

BTW,例子中的CharsetDecoder也是JavaNIO的一個(gè)新特性,所以大家應(yīng)該發(fā)現(xiàn)了一點(diǎn)哈,NIO的操作是面向緩沖區(qū)的(傳統(tǒng)I/O是面向流的)。

至此,我們了解了Channel與Buffer的基本用法。接下來(lái)要說(shuō)的是讓一個(gè)線程管理多個(gè)Channel的重要組件。

3.Selector

Selector是什么

Selector(選擇器)是一個(gè)特殊的組件,用于采集各個(gè)通道的狀態(tài)(或者說(shuō)事件)。我們先將通道注冊(cè)到選擇器,并設(shè)置好關(guān)心的事件,然后就可以通過(guò)調(diào)用select()方法,靜靜地等待事件發(fā)生。

通道有如下4個(gè)事件可供我們監(jiān)聽(tīng):

Accept:有可以接受的連接

Connect:連接成功

Read:有數(shù)據(jù)可讀

Write:可以寫(xiě)入數(shù)據(jù)了

為什么要用Selector

前文說(shuō)了,如果用阻塞I/O,需要多線程(浪費(fèi)內(nèi)存),如果用非阻塞I/O,需要不斷重試(耗費(fèi)CPU)。Selector的出現(xiàn)解決了這尷尬的問(wèn)題,非阻塞模式下,通過(guò)Selector,我們的線程只為已就緒的通道工作,不用盲目的重試了。比如,當(dāng)所有通道都沒(méi)有數(shù)據(jù)到達(dá)時(shí),也就沒(méi)有Read事件發(fā)生,我們的線程會(huì)在select()方法處被掛起,從而讓出了CPU資源。

使用方法

如下所示,創(chuàng)建一個(gè)Selector,并注冊(cè)一個(gè)Channel。

注意:要將Channel注冊(cè)到Selector,首先需要將Channel設(shè)置為非阻塞模式,否則會(huì)拋異常。

Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

register()方法的第二個(gè)參數(shù)名叫“interest set”,也就是你所關(guān)心的事件集合。如果你關(guān)心多個(gè)事件,用一個(gè)“按位或運(yùn)算符”分隔,比如

SelectionKey.OP_READ | SelectionKey.OP_WRITE

這種寫(xiě)法一點(diǎn)都不陌生,支持位運(yùn)算的編程語(yǔ)言里都這么玩,用一個(gè)整型變量可以標(biāo)識(shí)多種狀態(tài),它是怎么做到的呢,其實(shí)很簡(jiǎn)單,舉個(gè)例子,首先預(yù)定義一些常量,它們的值(二進(jìn)制)如下

可以發(fā)現(xiàn),它們值為1的位都是錯(cuò)開(kāi)的,因此對(duì)它們進(jìn)行按位或運(yùn)算之后得出的值就沒(méi)有二義性,可以反推出是由哪些變量運(yùn)算而來(lái)。怎么判斷呢,沒(méi)錯(cuò),就是“按位與”運(yùn)算。比如,現(xiàn)在有一個(gè)狀態(tài)集合變量值為0011,我們只需要判斷“0011&OP_READ”的值是1還是0就能確定集合是否包含OP_READ狀態(tài)。

然后,注意register()方法返回了一個(gè)SelectionKey的對(duì)象,這個(gè)對(duì)象包含了本次注冊(cè)的信息,我們也可以通過(guò)它修改注冊(cè)信息。從下面完整的例子中可以看到,select()之后,我們也是通過(guò)獲取一個(gè)SelectionKey的集合來(lái)獲取到那些狀態(tài)就緒了的通道。

一個(gè)完整實(shí)例

概念和理論的東西闡述完了(其實(shí)寫(xiě)到這里,我發(fā)現(xiàn)沒(méi)寫(xiě)出多少東西,好尷尬(⊙ˍ⊙)),看一個(gè)完整的例子吧。

這個(gè)例子使用JavaNIO實(shí)現(xiàn)了一個(gè)單線程的服務(wù)端,功能很簡(jiǎn)單,監(jiān)聽(tīng)客戶端連接,當(dāng)連接建立后,讀取客戶端的消息,并向客戶端響應(yīng)一條消息。

需要注意的是,我用字符‘\0′(一個(gè)值為0的字節(jié))來(lái)標(biāo)識(shí)消息結(jié)束。

單線程Server

public class NioServer {
	public static void main(String[] args) throws IOException {
		// 創(chuàng)建一個(gè)selector
		Selector selector = Selector.open();
		// 初始化TCP連接監(jiān)聽(tīng)通道
		ServerSocketChannel listenChannel = ServerSocketChannel.open();
		listenChannel.bind(new InetSocketAddress(9999));
		listenChannel.configureBlocking(false);
		// 注冊(cè)到selector(監(jiān)聽(tīng)其ACCEPT事件)
		listenChannel.register(selector, SelectionKey.OP_ACCEPT);
		// 創(chuàng)建一個(gè)緩沖區(qū)
		ByteBuffer buffer = ByteBuffer.allocate(100);
		while (true) {
			selector.select();
			//阻塞,直到有監(jiān)聽(tīng)的事件發(fā)生
			Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
			// 通過(guò)迭代器依次訪問(wèn)select出來(lái)的Channel事件
			while (keyIter.hasNext()) {
				SelectionKey key = keyIter.next();
				if (key.isAcceptable()) {
					// 有連接可以接受
					SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
					channel.configureBlocking(false);
					channel.register(selector, SelectionKey.OP_READ);
					System.out.println("與【" + channel.getRemoteAddress() + "】建立了連接!");
				} else if (key.isReadable()) {
					// 有數(shù)據(jù)可以讀取
					buffer.clear();
					// 讀取到流末尾說(shuō)明TCP連接已斷開(kāi),
					// 因此需要關(guān)閉通道或者取消監(jiān)聽(tīng)READ事件
					// 否則會(huì)無(wú)限循環(huán)
					if (((SocketChannel) key.channel()).read(buffer) == -1) {
						key.channel().close();
						continue;
					}
					// 按字節(jié)遍歷數(shù)據(jù)
					buffer.flip();
					while (buffer.hasRemaining()) {
						byte b = buffer.get();
						if (b == 0) {
							// 客戶端消息末尾的\0
							System.out.println();
							// 響應(yīng)客戶端
							buffer.clear();
							buffer.put("Hello, Client!\0".getBytes());
							buffer.flip();
							while (buffer.hasRemaining()) {
								((SocketChannel) key.channel()).write(buffer);
							}
						} else {
							System.out.print((char) b);
						}
					}
				}
				// 已經(jīng)處理的事件一定要手動(dòng)移除
				keyIter.remove();
			}
		}
	}
}

Client

這個(gè)客戶端純粹測(cè)試用,為了看起來(lái)不那么費(fèi)勁,就用傳統(tǒng)的寫(xiě)法了,代碼很簡(jiǎn)短。

要嚴(yán)謹(jǐn)一點(diǎn)測(cè)試的話,應(yīng)該并發(fā)運(yùn)行大量Client,統(tǒng)計(jì)服務(wù)端的響應(yīng)時(shí)間,而且連接建立后不要立刻發(fā)送數(shù)據(jù),這樣才能發(fā)揮出服務(wù)端非阻塞I/O的優(yōu)勢(shì)。

public class Client {
	public static void main(String[] args) throws Exception {
		Socket socket = new Socket("localhost", 9999);
		InputStream is = socket.getInputStream();
		OutputStream os = socket.getOutputStream();
		// 先向服務(wù)端發(fā)送數(shù)據(jù)
		os.write("Hello, Server!\0".getBytes());
		// 讀取服務(wù)端發(fā)來(lái)的數(shù)據(jù)
		int b;
		while ((b = is.read()) != 0) {
			System.out.print((char) b);
		}
		System.out.println();
		socket.close();
	}
}

總結(jié)

以上就是本文關(guān)于快速了解Java中NIO核心組件的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)內(nèi)容,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

  • FreeMarker如何調(diào)用Java靜態(tài)方法及靜態(tài)變量方法

    FreeMarker如何調(diào)用Java靜態(tài)方法及靜態(tài)變量方法

    這篇文章主要介紹了FreeMarker如何調(diào)用Java靜態(tài)方法及靜態(tài)變量方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java中創(chuàng)建線程的四種方法解析

    Java中創(chuàng)建線程的四種方法解析

    這篇文章主要介紹了Java中創(chuàng)建線程的四種方法解析,線程是Java編程語(yǔ)言中的一個(gè)重要概念,它允許程序在同一時(shí)間執(zhí)行多個(gè)任務(wù),線程是程序中的執(zhí)行路徑,可以同時(shí)執(zhí)行多個(gè)線程,每個(gè)線程都有自己的執(zhí)行流程,需要的朋友可以參考下
    2023-10-10
  • java compareTo和compare方法比較詳解

    java compareTo和compare方法比較詳解

    這篇文章主要介紹了java compareTo和compare方法比較詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • Java 數(shù)組內(nèi)置函數(shù)toArray詳解

    Java 數(shù)組內(nèi)置函數(shù)toArray詳解

    這篇文章主要介紹了Java 數(shù)組內(nèi)置函數(shù)toArray詳解,文本詳細(xì)的講解了toArray底層的代碼和文檔,需要的朋友可以參考下
    2021-06-06
  • 一文徹底搞定Java哈希表和哈希沖突

    一文徹底搞定Java哈希表和哈希沖突

    本文介紹了什么是哈希表?什么是哈希函數(shù)?什么是哈希沖突?三個(gè)問(wèn)題的解決方案,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • java實(shí)現(xiàn)開(kāi)根號(hào)的運(yùn)算方式

    java實(shí)現(xiàn)開(kāi)根號(hào)的運(yùn)算方式

    這篇文章主要介紹了java實(shí)現(xiàn)開(kāi)根號(hào)的運(yùn)算方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • java實(shí)現(xiàn)單機(jī)限流

    java實(shí)現(xiàn)單機(jī)限流

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)單機(jī)限流,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Spring中MVC模塊代碼詳解

    Spring中MVC模塊代碼詳解

    這篇文章主要介紹了Spring中MVC模塊代碼詳解,涉及Controller的簡(jiǎn)單介紹,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-11-11
  • Mybatis-Plus的SQL語(yǔ)句組拼原理說(shuō)明

    Mybatis-Plus的SQL語(yǔ)句組拼原理說(shuō)明

    這篇文章主要介紹了Mybatis-Plus的SQL語(yǔ)句組拼原理說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java設(shè)計(jì)模式的策略模式簡(jiǎn)析

    Java設(shè)計(jì)模式的策略模式簡(jiǎn)析

    這篇文章主要介紹了Java設(shè)計(jì)模式的策略模式簡(jiǎn)析,策略模式中定義了一系列的算法族,算法族指的是類(lèi)似于一系列的行為、策略,策略模式將一系列的行為封裝成類(lèi),既可以說(shuō)是將每一種相類(lèi)似的行為都封裝成一個(gè)類(lèi),也有可能存在特殊的不進(jìn)行封裝的行為,需要的朋友可以參考下
    2023-12-12

最新評(píng)論