學習設計模式《十七》——狀態模式

一、基礎概念

????????狀態模式的本質是【根據狀態來分離和選擇行為】。

????????狀態模式的定義:允許一個對象在其內部狀態改變時改變它的行為;對象看起來似乎修改了它的類

認識狀態模式
序號認識狀態模式說明
1狀態和行為通常指的是對象實例的屬性的值;而行為指的就是對象的功能(具體的說行為大多對應到方法上);狀態模式的功能【分離狀態行為,通過維護狀態的變化,來調用不同狀態對應的不同功能】(即:狀態和行為是相關聯的,它們的關系可以描述為:狀態決定行為);由于狀態是在運行期間被改變的,因此行為也會在運行期間根據狀態的改變而改變;看起來同一個對象,在不同的運行時刻,行為是不一樣的,就像是類被修改了一樣。
2行為的平行性指的是【各個狀態的行為所處的層次是一樣的,相互獨立的,沒有關聯的,是根據不同的狀態決定到底走平行線的哪一條】行為是不同的,當然對應的實現也是不同的,相互之間不可以替換。平等性強調的時可替換性,大家是同一行為的不同描述或實現;因此在同一個行為發生的時候,可以根據條件挑選任意一個實現來進行相應的處理。【大家可能會發現狀態模式的結構和策略模式的結構完全一樣,但是,它們的目的、實現、本質卻是完全不一樣的。還有行為之間的特性也是狀態模式和策略模式一個很重要的區別,?狀態模式的行為是平行性的,不可相互替換的。二策略模式的行為是平等性的,是可以相互替換的】
3上下文和狀態處理對象在狀態模式中,上下文是持有狀態的對象,但是上下文自身并不處理跟狀態相關的行為,而是把處理狀態的功能委托給了狀態對應的狀態處理類來處理。在具體的狀態處理類中經常需要獲取上下文自身的數據,甚至在必要的時候會回調上下文的方法,因此,通常將上下文自身當做一個參數傳遞給具體的狀態處理類客戶端一般只和上下文交互。客戶端可以用狀態對象來配置一個上下文,一旦配置完畢,就不再需要和狀態對象打交道了。客戶端通常不負責運行期間狀態的維護,也不負責決定后續到底使用哪一個具體的狀態處理對象。
4

不完美的開放封閉原則

(OCP,Open Closed Principle)體驗

如何實現擴展?

比如我們現在拓展了正常投票狀態給正常投票的用戶給予積分獎勵;但是怎么讓VoteManager使用這個新的實現類呢?按照目前的實現,只能去修改VoteManager這個類的Vote方法。這樣一來雖然實現了我們的功能,但是并沒有完全遵守OCP原則(其實在我們實際設計開發的時候,設計原則是指導,但是并不一定要完全遵守,完全遵守設計原則幾乎是不可能完成的任務)

5創建和銷毀狀態對象

在使用狀態模式的時候,需要考慮究竟何時創建和銷毀狀態對象?通常有如下三種方式:
《1》當需要使用狀態對象的時候創建,使用完成后就銷毀它們;
《2》提前創建它們并且始終不銷毀;
《3》采用延遲加載和緩存合用的方式,就是當第一次需要使用狀態對象的時候創建,使用完成后并不銷毀對象,而是把這個對象緩存起來,等待下一次使用,而在合適的時候,會由緩存框架銷毀狀態對象。
如何選擇呢?
《1》如果要進入的狀態在運行時是不可知的,而且上下文是比較穩定的,不會經常改變狀態,且使用不頻繁,就采用第一種方式;
《2》如果狀態改變很頻繁(即需要頻繁的創建狀態對象)且狀態對象還存儲著大量數據信息,則建議使用第二種方式
《3》如果無法確定狀態改變是否頻繁,而且有些狀態對象的狀態數據量大,有些較小,一切都是未知的,建議使用第三種方式。

?實際上,在開發過程中,第三種方式是首選的(因為它兼顧了前兩種方式的優點且又避免了它們的缺點,幾乎可以適應各種情況需要)【只是這個方案在實現的時候,需要實現一個合理的緩存框架,而且需要考慮多線程并發的問題,因為需要由緩存框架來在合適的時候銷毀狀態對象,因此實現上難度稍大】

6狀態的維護和轉換控制狀態的維護指【維護狀態的數據,給狀態設置不同的狀態值】狀態轉換指【根據狀態的變化來選擇不同的狀態處理對象】在狀態模式中,通常由兩個地方可以進行狀態的維護和轉換控制:
《1》在上下文中因為狀態本身通常被實現為上下文對象的狀態,因此可以在上下文中進行狀態維護,當然也可以控制狀態的轉換了。
《2》在狀態的處理類中:當每個狀態處理對象處理完自身狀態所對應的功能后,可以根據需要指定后繼的狀態,以便應用能正確處理后續的請求。
那么到底如何選擇這兩種方式呢?
《1》如果狀態轉換的規則是一定的,一般不需要進行什么擴展規則,適合在上下文中統一進行狀態的維護
《2》如果狀態的轉換取決于前一個狀態動態處理的結果(或者是依賴于外部的數據)為了增加靈活性,此時在狀態處理類中進行狀態的維護
狀態模式的優缺點
序號狀態模式的優點狀態模式的缺點
1

簡化應用邏輯控制

????????狀態模式使用單獨的類來封裝一個狀態的處理。如果把一個大的程序控制分為很多小塊,每塊定義一個狀態來代表,那么就可以把這些邏輯控制的代碼分散到很多單獨的類中去,這樣就把著眼點從執行狀態提高到整個對象狀態,使得代碼結構化和意圖更清晰,從而簡化應用的邏輯控制。對于依賴于狀態的if-else,理論上來講,也可以改變成應用狀態模式來實現,把每個if或else塊定義一個狀態來代表,那么就可以把塊內的功能代碼移動到狀態處理類中,從而減少if-else,避免出現巨大的條件語句

一個狀態對應一個狀態處理類,會使得程序引入太多的狀態類,使程序變得雜亂
2

更好的分離狀態和行為

????????狀態模式通過設置所有狀態類的公共接口,把狀態和狀態對應的行為分離開,把所有與一個特定的狀態相關的行為都放入到一個對象中,使得程序在控制的時候,只需要關心狀態的切換,而不用關心這個狀態對應的真正處理。

3

更好的擴展性

????????引入了狀態處理的公共接口后,使得擴展新的狀態變得非常容易,只需要新增加一個實現狀態處理的公共接口的實現類,然后在進行狀態維護的地方,設置狀態編號到這個新的狀態即可。

4

顯示化進行狀態轉換

????????狀態模式引入獨立對象,使得狀態的轉換變得更加明確,而且狀態對象可以保證上下文不會發生內部狀態不一致的情況,因為上下文中只有一個變量來記錄狀態對象,只要為這一個變量賦值就可以了。

????????何時選用狀態模式?

????????1、如果一個對象的行為取決于它的狀態,而且必須在運行時刻根據狀態來改變它的行為,可以使用狀態模式,來把狀態和行為分離開。雖然分離開了,但狀態和行為是有對應關系的,可以在運行期間,通過改變狀態,就能夠調用到該狀態對應的狀態處理對象上去,從而改變對象的行為。
????????
2、如果一個操作中含有龐大的多分支語句,而且這些分支依賴于該對象的狀態,可以使用狀態模式,把各個分支的處理分散包裝到單獨的對象處理類中,這樣,這些分支對應的對象就可以不依賴于其他對象而獨立變化了。

二、狀態模式示例

????????業務需求:現在有一個在線投票的系統,需要實現控制同一個用戶只能投一票功能;如果一個用戶反復投票,且投票的次數超過5次,則判斷為惡意刷票,要取消該用戶投票的資格,同時需要取消他所投的票數。如果一個用戶的投票次數超過了8次,將進入黑名單,禁止在登錄和使用系統。

?2.1、不使用模式的示例

分析需求,在這個投票需求中,其實分為四種情況:

1、用戶正常投票;

2、用戶正常投票后,有意或無意地重復投票;

3、用戶惡意投票;

4、黑名單用戶。

《1》投票管理類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern
{/// <summary>/// 投票管理/// </summary>internal class VoteManager{//記錄用戶投票的結果<用戶名稱,投票選項>private Dictionary<string,string>voteResultDic= new Dictionary<string,string>();//記錄用戶投票次數<用戶名稱,投票次數>private Dictionary<string,int>voteCountDic= new Dictionary<string,int>();//用戶投票次數int oldVoteCount = 0;/// <summary>/// 投票方法/// </summary>/// <param name="user">投票用戶</param>/// <param name="voteItem">投票選項</param>public void Vote(string user,string voteItem){//1-若投票次數容器不包含該用戶則新增否則從容器獲取后再操作if (!voteCountDic.ContainsKey(user)){if (oldVoteCount == 0){oldVoteCount += 1;voteCountDic.Add(user, oldVoteCount);}}else{oldVoteCount= voteCountDic[user];if (oldVoteCount>=1){oldVoteCount += 1;voteCountDic[user] = oldVoteCount;}}//判斷用戶投票的類型(判斷是正常投票、重復投票還是惡意投票)if (oldVoteCount == 1){//正常投票,則記錄到投票記錄voteResultDic.Add(user, voteItem);Console.WriteLine($"恭喜你【{user}】投給【{voteItem}】【{voteCountDic[user]}】票成功");}else if (oldVoteCount > 1 && oldVoteCount < 5){//重復投票,暫不處理Console.WriteLine($"請不要重復投票,【{user}】已經投給【{voteItem}】票【{oldVoteCount}】次");} else if (oldVoteCount>=5 && oldVoteCount<8){//惡意投票,取消用戶投票資格,并取消投票記錄string voteResult = voteResultDic[user];if (!string.IsNullOrEmpty(voteResult)){voteResultDic[user]="";}Console.WriteLine($"你有惡意刷票行為,取消投票資格并清空投票記錄;【{user}】已投給【{voteItem}】票【{voteCountDic[user]}】次");}else if (oldVoteCount>=8){//記入黑名單,禁止登錄系統Console.WriteLine($"進入黑名單,禁止登錄和使用本系統;【{user}】已投給【{voteItem}】票【{voteCountDic[user]}】次");}}}//Class_end
}

《2》客戶端測試

using StatePattern.StateDemoThree;namespace StatePattern
{internal class Program{static void Main(string[] args){VoteManagerTest();Console.ReadLine();}/// <summary>/// 投票管理測試/// </summary>private static void VoteManagerTest(){Console.WriteLine("---投票管理測試---");VoteManager voteManager = new VoteManager();for (int i = 0; i < 10; i++){voteManager.Vote("張三","A");}}}//Class_end 
}

《3》運行結果

????????現在我們的實現是達到業務要求了;但是在Vote()方法中有很多的判斷,且每個判斷對應的功能處理都放在一起,有些雜亂現在的問題是:

《1》如果現在需要修改某種投票情況所對應的具體功能處理,那就需要在Vote()方法中尋找到相應的代碼塊,然后進行改動。

《2》如果要添加新的功能(如投票超過8次但不足10次,給個機會,只是禁止登錄和使用系統3天;如果再犯才永久封號,這樣該怎么處理?【這就需要修改投票管理代碼,在if-else結構中再添加另外一個else-if的塊進行處理】)。

????????這兩種情況,不管那種都需要在原有的代碼中修改;那么該如何實現才能夠做到【即能夠容易地給Vote()方法添加新的功能,又能夠很方便地修改已有的功能呢?】

?2.2、使用狀態模式的示例1——上下文統一管理狀態及其具體狀態行為的調用

使用狀態模式解決上面問題的思路是:

????????我們發現其實用戶投票分為了四種投票狀態,且各個狀態和對應的功能具有很強的對應性(即:每個狀態下的各自處理是不同的,不存在相互替換的可能);

????????那么為了解決上面提出的問題,一個設計就是:把狀態和狀態對應的行為從原來的雜亂代碼中分離出來,把每個狀態所對應的功能都封裝在一個單獨的類里面,這樣選擇不同處理的時候,其實就是在選擇不同的狀態處理類。為了統一操作這些不同的狀態類,則定義一個狀態接口來約束它們,這樣外部就可以面向這個統一狀態接口編程,而無須關心具體的狀態類實現了。這樣一來,要修改某種投票情況所對應的具體功能處理,只需要直接修改或擴展某個狀態處理類就可以了。

? 2.2.1、定義投票接口——規范對外提供的行為

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{/// <summary>/// 投票狀態接口/// </summary>internal interface IVoteState{//處理狀態對象的行為void Vote(string user,string voteItem,VoteManager voteManager);}//Interface_end
}

? 2.2.2、具體各種投票狀態對應處理類的實現

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{/// <summary>/// 正常投票/// </summary>internal class NormalVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//正常投票,則記錄到投票記錄if (!voteManager.GetVoteResultDic().ContainsKey(user)){voteManager.GetVoteResultDic().Add(user,voteItem);}Console.WriteLine($"恭喜你【{user}】投給【{voteItem}】票成功");}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{/// <summary>/// 重復投票/// </summary>internal class RepeatVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//重復投票,不做處理Console.WriteLine($"請不要重復投票,【{user}】已經投給【{voteItem}】票");}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{internal class SpiteVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//惡意投票,取消用戶投票資格,并取消投票記錄if (voteManager.GetVoteResultDic().ContainsKey(user)){voteManager.GetVoteResultDic()[user] = "";}Console.WriteLine($"你有惡意刷票行為,取消投票資格并清空投票記錄;【{user}】已投給【{voteItem}】票");}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{internal class BlackVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//記入黑名單,禁止登錄系統Console.WriteLine($"進入黑名單,禁止登錄和使用本系統;【{user}】已投給【{voteItem}】票");}}//Class_end
}

? 2.2.3、投票管理實現——相當于狀態模式的上下文

投票管理是實現對各種狀態的判斷與調用管理。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{/// <summary>/// 投票管理/// </summary>internal class VoteManager{//持有狀態處理對象private IVoteState voteState = null;//記錄用戶投票的結果<用戶名稱,投票選項>private Dictionary<string, string> voteResultDic = new Dictionary<string, string>();//記錄用戶投票次數<用戶名稱,投票次數>private Dictionary<string, int> voteCountDic = new Dictionary<string, int>();/// <summary>/// 獲取記錄用戶投票的結果容器/// </summary>/// <returns></returns>public Dictionary<string, string> GetVoteResultDic(){return voteResultDic;}//投票public void Vote(string user,string voteItem){int oldVoteCount = 0;if (!voteCountDic.ContainsKey(user)){oldVoteCount += 1;voteCountDic.Add(user,oldVoteCount);}else{oldVoteCount= voteCountDic[user];oldVoteCount += 1;voteCountDic[user]= oldVoteCount;}if (oldVoteCount == 1){voteState = new NormalVoteState();}else if (oldVoteCount > 1 && oldVoteCount < 5){voteState = new RepeatVoteState();}else if (oldVoteCount >= 5 && oldVoteCount < 8){voteState = new SpiteVoteState();}else if (oldVoteCount >= 8){voteState = new BlackVoteState();}//然后調用狀態對象進行相應的操作voteState.Vote(user,voteItem,this);}}//Class_end
}

? 2.2.4、客戶端測試


using StatePattern.StateDemoThree;namespace StatePattern
{internal class Program{static void Main(string[] args){VoteManagerByStatePattern();Console.ReadLine();}/// <summary>/// 使用狀態模式進行投票管理測試/// </summary>private static void VoteManagerByStatePattern(){Console.WriteLine("---使用狀態模式進行投票管理測試---");StateDemoOne.VoteManager voteManager = new StateDemoOne.VoteManager();for (int i = 0; i < 10; i++){voteManager.Vote("張三", "A");}}}//Class_end 
}

? 2.2.5、運行結果

在這個狀態模式實現的示例中可以看出:【狀態的轉換是在內部實現的,主要在狀態模式內部(VoteManager)里面維護】(如:對于投票的人員,任何時候他的操作都是投票,但是投票管理對象的處理卻不一定一樣,會根據投票的次來判斷狀態,然后根據狀態去選擇不同的處理)。?

? 2.2.6、不完美的OCP擴展

?比如我們現在需要對正常投票狀態對應的功能進行修改(即:

1、對正常的投票用戶給予積分獎勵,那么只需要擴展正常投票的狀態對應類;但是VoteManager類里面的維護還是需要修改原有代碼將原有的NormalVoteState()修改NormalVoteStateExtand();

2、需要給投票超過8次但是不足10次的,給個機會,只是禁止登錄和使用系統3天,如果再犯才進入黑名單【要實現這個功能,需要對原有的投票超過8次的狀態判定VoteManager類里面進行修改(實現超過8次但不足10次)是黑名單警告,最后才是黑名單;然后在實現一個黑名單警告的具體處理邏輯】)。

《1》擴展正常投票類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{internal class NormalVoteStateExtand:NormalVoteState,IVoteState{public new void Vote(string user, string voteItem, VoteManager voteManager){//先調用已有的功能base.Vote(user, voteItem, voteManager);//然后在給與積分獎勵Console.WriteLine("獎勵積分10分");}}//Class_end
}

《2》實現黑名單警告類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{internal class BlackWarnVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//待進入黑名單警告狀態Console.WriteLine("禁止登錄和使用系統3天");}}//Class_end
}

《3》投票管理類投票狀態及其具體類使用的修改

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoOne
{/// <summary>/// 投票管理/// </summary>internal class VoteManager{//持有狀態處理對象private IVoteState voteState = null;//記錄用戶投票的結果<用戶名稱,投票選項>private Dictionary<string, string> voteResultDic = new Dictionary<string, string>();//記錄用戶投票次數<用戶名稱,投票次數>private Dictionary<string, int> voteCountDic = new Dictionary<string, int>();/// <summary>/// 獲取記錄用戶投票的結果容器/// </summary>/// <returns></returns>public Dictionary<string, string> GetVoteResultDic(){return voteResultDic;}//投票public void Vote(string user,string voteItem){int oldVoteCount = 0;if (!voteCountDic.ContainsKey(user)){oldVoteCount += 1;voteCountDic.Add(user,oldVoteCount);}else{oldVoteCount= voteCountDic[user];oldVoteCount += 1;voteCountDic[user]= oldVoteCount;}if (oldVoteCount == 1){//voteState = new NormalVoteState();voteState = new NormalVoteStateExtand();}else if (oldVoteCount > 1 && oldVoteCount < 5){voteState = new RepeatVoteState();}else if (oldVoteCount >= 5 && oldVoteCount < 8){voteState = new SpiteVoteState();}//else if (oldVoteCount >= 8)//{//    voteState = new BlackVoteState();//}else if (oldVoteCount >= 8 && oldVoteCount < 10){voteState = new BlackWarnVoteState();}else if (oldVoteCount >= 10){voteState = new BlackVoteState();}//然后調用狀態對象進行相應的操作voteState.Vote(user,voteItem,this);}}//Class_end
}

《4》客戶端不用修改


using StatePattern.StateDemoThree;namespace StatePattern
{internal class Program{static void Main(string[] args){VoteManagerByStatePattern();Console.ReadLine();}/// <summary>/// 使用狀態模式進行投票管理測試/// </summary>private static void VoteManagerByStatePattern(){Console.WriteLine("---使用狀態模式進行投票管理測試---");StateDemoOne.VoteManager voteManager = new StateDemoOne.VoteManager();for (int i = 0; i < 10; i++){voteManager.Vote("張三", "A");}}}//Class_end 
}

《5》運行結果

2.3、使用狀態模式的示例2——在每個具體的狀態行為下調用下一個狀態行為

? 2.3.1、定義投票接口——規范對外提供的行為

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{/// <summary>/// 投票狀態接口(規范投票狀態對外的相關行為)/// </summary>internal interface IVoteState{//處理狀態對象的行為void Vote(string user,string voteItem,VoteManager voteManager);}//Interface_end
}

? 2.3.2、具體各種投票狀態對應處理類的實現

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{internal class NormalVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//正常投票,則記錄到投票記錄if (!voteManager.GetVoteResultDic().ContainsKey(user)){voteManager.GetVoteResultDic().Add(user, voteItem);}Console.WriteLine($"恭喜你【{user}】投給【{voteItem}】票成功");//正常投票完成,維護下一個狀態,同一個人在投票就重復了if (!voteManager.GetVoteStateDic().ContainsKey(user)){voteManager.GetVoteStateDic().Add(user, new RepeatVoteState());}else{voteManager.GetVoteStateDic()[user] = new RepeatVoteState();}}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{internal class RepeatVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//重復投票,不做處理Console.WriteLine($"請不要重復投票,【{user}】已經投給【{voteItem}】票");//重復投票完成,維護下一個狀態,重復投票到5次,就算惡意投票了;注意這里是判斷大于等于4,因為在這里設置的是下一個狀態if (voteManager.GetVoteCountDic()[user]>=4){if (!voteManager.GetVoteStateDic().ContainsKey(user)){voteManager.GetVoteStateDic().Add(user, new SpiteVoteState());}else{voteManager.GetVoteStateDic()[user]=new SpiteVoteState();}}}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{internal class SpiteVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//惡意投票,取消用戶投票資格,并取消投票記錄if (voteManager.GetVoteResultDic().ContainsKey(user)){voteManager.GetVoteResultDic()[user] = "";}Console.WriteLine($"你有惡意刷票行為,取消投票資格并清空投票記錄;【{user}】已投給【{voteItem}】票");//惡意投票完成,維護下一個狀態,投票到8次則進入黑名單,這里的判斷是大于等于7if (voteManager.GetVoteCountDic()[user]>=7){if (!voteManager.GetVoteStateDic().ContainsKey(user)){voteManager.GetVoteStateDic().Add(user, new BlackVoteState());}else{voteManager.GetVoteStateDic()[user] = new BlackVoteState();}}}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{internal class BlackVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//記入黑名單,禁止登錄系統Console.WriteLine($"進入黑名單,禁止登錄和使用本系統;【{user}】已投給【{voteItem}】票");}}//Class_end
}

? 2.2.3、投票管理實現——相當于狀態模式的上下文

?這里需要在投票管理類中新增一個投票狀態容器,用來記錄每個用戶對應的投票狀態。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{/// <summary>/// 投票管理/// </summary>internal class VoteManager{//持有狀態處理對象private IVoteState voteState = null;//記錄當前每個用戶對應的狀態處理對象,每個用戶當前的狀態是不同的<用戶名稱,當前對應的狀態處理對象>private Dictionary<string,IVoteState> voteStateDic = new Dictionary<string,IVoteState>();//記錄用戶投票的結果<用戶名稱,投票的選項>private Dictionary<string ,string> voteResultDic= new Dictionary<string ,string>();//記錄用戶投票的次數private Dictionary<string,int>voteCountDic= new Dictionary<string ,int>();//獲取用戶狀態的容器public Dictionary<string, IVoteState> GetVoteStateDic(){return voteStateDic;}//獲取用戶投票的結果容器public Dictionary<string, string> GetVoteResultDic(){return voteResultDic;}//獲取用戶投票的次數容器public Dictionary<string, int> GetVoteCountDic(){return voteCountDic;}//投票public void Vote(string user,string voteItem){int oldVoteCount = 0;//1-先為該用戶增加投票次數if (!voteCountDic.ContainsKey(user)){oldVoteCount += 1;voteCountDic.Add(user, oldVoteCount);}else{oldVoteCount = voteCountDic[user];oldVoteCount += 1;voteCountDic[user] = oldVoteCount;}//2-獲取該用戶的投票狀態voteState = new NormalVoteState();//如果沒有投票狀態,說明還沒有投過票,那就初始化一個正常的投票狀態if (!voteStateDic.ContainsKey(user)){voteStateDic.Add(user, voteState);}else{voteState=voteStateDic[user];}//調用投票方法進行操作voteState.Vote(user,voteItem,this);}}//Class_end
}

? 2.2.4、客戶端測試

using StatePattern.StateDemoThree;namespace StatePattern
{internal class Program{static void Main(string[] args){VoteManagerTwoByStatePattern();Console.ReadLine();}/// <summary>/// 使用狀態模式進行投票管理測試2/// </summary>private static void VoteManagerTwoByStatePattern(){Console.WriteLine("---使用狀態模式進行投票管理測試2---");StateDemoTwo.VoteManager voteManager = new StateDemoTwo.VoteManager();for (int i = 0; i < 10; i++){voteManager.Vote("張三", "A");}}}//Class_end 
}

? 2.2.5、運行結果

? 2.2.6、不完美的OCP擴展

????????新增需求:現在需要實現投票超過8次但不足10次的,給個機會,只是禁止登錄和使用系統3天,如果再犯,在拉入黑名單。

《1》新增警告狀態類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{internal class BlackWarnVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//待進入黑名單警告狀態Console.WriteLine("禁止登錄和使用系統3天");//待進入黑名單警告處理完成,維護下一個狀態,投票到10次,就進入黑名單,這里的判斷是大于等于9if (voteManager.GetVoteCountDic()[user]>=9){if (!voteManager.GetVoteStateDic().ContainsKey(user)){voteManager.GetVoteStateDic().Add(user, new BlackVoteState());}else{voteManager.GetVoteStateDic()[user] = new BlackVoteState();}}}}//Class_end
}

?《2》修改使用到原來拉入黑名單的惡意刷票類里面修改下一步操作為警告狀態

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoTwo
{internal class SpiteVoteState : IVoteState{public void Vote(string user, string voteItem, VoteManager voteManager){//惡意投票,取消用戶投票資格,并取消投票記錄if (voteManager.GetVoteResultDic().ContainsKey(user)){voteManager.GetVoteResultDic()[user] = "";}Console.WriteLine($"你有惡意刷票行為,取消投票資格并清空投票記錄;【{user}】已投給【{voteItem}】票");//惡意投票完成,維護下一個狀態,投票到8次則進入黑名單,這里的判斷是大于等于7if (voteManager.GetVoteCountDic()[user]>=7){if (!voteManager.GetVoteStateDic().ContainsKey(user)){//voteManager.GetVoteStateDic().Add(user, new BlackVoteState());voteManager.GetVoteStateDic().Add(user, new BlackWarnVoteState());}else{//voteManager.GetVoteStateDic()[user] = new BlackVoteState();voteManager.GetVoteStateDic()[user] = new BlackWarnVoteState();}}}}//Class_end
}

《3》客戶端測試——不變

using StatePattern.StateDemoThree;namespace StatePattern
{internal class Program{static void Main(string[] args){VoteManagerTwoByStatePattern();Console.ReadLine();}/// <summary>/// 使用狀態模式進行投票管理測試2/// </summary>private static void VoteManagerTwoByStatePattern(){Console.WriteLine("---使用狀態模式進行投票管理測試2---");StateDemoTwo.VoteManager voteManager = new StateDemoTwo.VoteManager();for (int i = 0; i < 10; i++){voteManager.Vote("張三", "A");}}}//Class_end 
}

《4》運行結果

?2.4、可使用數據庫來維護狀態

????????在實際開發中,還可以使用數據庫來維護狀態(即:在數據庫中存儲一個狀態的識別數據【將維護下一個狀態演化成了維護下一個狀態的識別數據(如狀態編碼)】)。

如果使用數據庫來維護狀態,實現思路如下:

????????《1》在每個具體的狀態處理類中,原本在處理完成后,需要判斷下一個狀態是什么,然后在創建下一個狀態對象,并設置會上下文中。【如果使用數據庫的方式,就不用創建下一個狀態對象,也不用設置會上下文中,而是把下一個狀態對應的編碼記入到數據庫中就可以了】。

????????《2》在上下文(如:VoteManager這個投票管理類中,則不用記錄所有用戶狀態的容器,而是直接從數據庫中獲取該用戶當前對應的狀態編碼,然后根據狀態編碼創建出對應的狀態對象即可);

????????《3》如果向數據庫中存儲下一個狀態對象的編碼,那么上下文中就不再需要持有狀態對象了,相當于把這個功能放到數據庫中了但是需要注意,數據庫存儲的只是狀態編碼,而不是狀態對象,獲取到數據庫中的狀態編碼后,在程序中仍然需要根據狀態編碼去創建對應的狀態對象】(如果想要程序更加通用一些,可以通過配置文件來配置狀態編碼和對應的狀態處理類【也可以直接在數據庫中記錄狀態編碼和對應的狀態處理類,這樣在上下文中,先獲取下一個狀態的狀態編碼,然后根據狀態編碼去獲取對應的類,然后通過反射來創建具體的狀態對象,這樣就避免了一長串的if-else;且以后再添加新的狀態編碼和狀態處理對象也不用修改代碼了】

?2.5、模擬工作流——請假流程

????????業務需求:有一個請假流程,流程內容為當某個人提出請假申請,先由項目經理審批,如果項目經理同意審批直接結束,再查看請假的天數是否超過3天,項目經理的審批權限最多只有3天,如果請假天數在3天內,那么審批也直接結束;否則就提交給部門經理;部門經理審核通過后,無論是否同意,審批都直接結束。業務流程圖如下:

?思路分析:

????????把請假單在流程中的各個階段狀態分析出來(即:該請假單的狀態有:等待項目經理審核、等待部門經理審核、審核結束)詳細的狀態驅動流程如下:

《1》請假人填寫請假單,提交請假單,此時請假單的狀態是等待項目經理審核狀態;

《2》當項目經理審核完成后,若不同意,則請假單的狀態是審核結束狀態;如果同意且請假天數在3天內,請假單的狀態是審核結束狀態;如果同意且請假天數大于3天,則請假單的狀態是等待部門經理審核狀態;

《3》當部門經理審核完成后,無論是否同意,請假單的狀態都是審核結束了。

????????既然可以把流程看作是狀態驅動的,那么自然可以自然地使用狀態模式,每次當相應的工作人員完成工作,請求流程響應的時候,流程處理的對象會根據當前所處的狀態,把流程處理委托給相應狀態對象去處理

? 2.5.1、定義狀態處理機——作為公共的上下文

????????這里定義的狀態處理機相當于上下文,提供基礎的、公共功能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 公共狀態處理(相當于狀態模式的Context上下文)/// 包含所有流程使用狀態模式時的公共功能/// </summary>internal class StateMachine{/// <summary>/// 持有的狀態對象/// </summary>public IState? State { get; set; }/// <summary>/// 創建流處理所需的業務數據模型(這里不知道具體類型,可使用泛型或object)/// </summary>public object? BusinessModel { get; set; }/// <summary>/// 執行工作,在客戶完成自己的業務工作后調用/// </summary>public void Dowork(){this.State.Dowork(this);}}//Class_end
}

? 2.5.2、定義狀態的公共接口——規范對外提供的功能

????????這個接口定義的處理流程功能所涉及到的業務數據就統一從上下文中傳遞而來:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 公共狀態接口/// </summary>internal interface IState{//執行狀態對象的功能處理void Dowork(StateMachine stateMachine);}//Interface_end
}

? 2.5.3、定義請假單數據模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 請假單/// </summary>internal class LeaveRequestModel{/// <summary>/// 請假人/// </summary>public string? User { get; set; }/// <summary>/// 請假開始時間/// </summary>public string? BeginDate { get; set; }/// <summary>/// 請假天數/// </summary>public int? LeaveDays { get;set; }/// <summary>/// 審核結果/// </summary>public string? AuditResult { get; set; }}//Class_end
}

? 2.5.4、定義處理客戶端請求的上下文

????????雖然我們這里的實現沒有擴展公共的上下文功能,但還是新定義了請假的上下文,表示可以添加自己的處理數據內容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 客戶端請求的上下文【雖然這里并不需要擴展狀態機,但還是繼承一下狀態機,表示可以添加自己的處理】/// </summary>/// <typeparam name="T"></typeparam>internal class LeaveRequestContext:StateMachine{//在上下文這里可以擴展與自己流程相關的處理}//Class_end
}

? 2.5.5、定義處理請假流程的狀態接口

????????雖然我們這里也不需要擴展公共狀態的接口功能,但還是繼承狀態接口,表示可以自己擴展請假狀態功能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 請假狀態接口【雖然這里不需要擴展狀態功能,但還是繼承一下狀態,表示可以添加自己的處理】/// </summary>/// <typeparam name="T"></typeparam>internal interface ILeaveRequestState: IState{//這里可以擴展與自己流程相關的處理}//Interface_end
}

? 2.5.6、實現各個具體的狀態對象

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 項目經理審核(項目經理審核后可能對應部門經理審核;或者是審核結束后的一種)/// </summary>internal class ProjectManagerState : ILeaveRequestState{public void Dowork(StateMachine stateMachine){//1-創建業務對象模型LeaveRequestModel model = (LeaveRequestModel)stateMachine.BusinessModel;//2-業務處理,把審核結果保存到數據庫中//3-分解選擇的結果和條件設置下一步驟if ("同意".Equals(model?.AuditResult)){if (model.LeaveDays > 3){//如果請假天數大于3天,且項目經理同意則提交部門經理stateMachine.State = new DepartmentManagerState();}else{//如果請假天數在3天及其以內,就由項目經理做主審批后轉為結束狀態stateMachine.State = new AuditOverState();}}else{//項目經理不同意的話,也就不用提交給部門經理了,直接轉為審核結束狀態stateMachine.State = new AuditOverState();}//4-給申請人增加一個提示,讓他可以查看當前的最新審核結果}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 處理部門經理的審核(處理后對應審核結束狀態)/// </summary>internal class DepartmentManagerState : ILeaveRequestState{public void Dowork(StateMachine stateMachine){//1-先把業務模型創建出來LeaveRequestModel model = (LeaveRequestModel)stateMachine.BusinessModel;//2-業務處理,將審核結果保存到數據庫中//3-部門經理審核通過后,直接轉向審核結束狀態stateMachine.State = new AuditOverState();//4-給申請人增加一個提示,讓他可以查看當前的最新審核結果}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 處理審核結束狀態/// </summary>internal class AuditOverState : ILeaveRequestState{public void Dowork(StateMachine stateMachine){//1-先把業務模型創建出來LeaveRequestModel model = (LeaveRequestModel)stateMachine.BusinessModel;//2-業務處理,在數據中記錄整個流程結束}}//Class_end
}

? 2.5.7、改進各個具體的狀態對象可以運行

????????由于前面的各個具體狀態對象沒有數據庫實現部分,且沒有對應的UI界面。因此我們這里就改造為在命令行界面模擬用戶輸入數據。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 項目經理審核(項目經理審核后可能對應部門經理審核;或者是審核結束后的一種)/// </summary>internal class ProjectManagerState2 : ILeaveRequestState{public void Dowork(StateMachine stateMachine){//1-創建業務對象模型LeaveRequestModel model = (LeaveRequestModel)stateMachine.BusinessModel;//模擬用戶處理界面,通過控制臺讀取和顯示數據Console.WriteLine("項目經理審核中,請稍后。。。");Console.WriteLine($"【{model?.User}】申請從【{model?.BeginDate}】開始請假【{model?.LeaveDays}】天,請審核(1:同意;2:不同意)");string? strInput=Console.ReadLine();if (!string.IsNullOrEmpty(strInput)){//設置會上下文中string result = "不同意";if ("1".Equals(strInput)){result = "同意";}model.AuditResult = result;}//2-業務處理,把審核結果保存到數據庫中//3-分解選擇的結果和條件設置下一步驟if ("同意".Equals(model?.AuditResult)){if (model.LeaveDays > 3){//如果請假天數大于3天,且項目經理同意則提交部門經理stateMachine.State = new DepartmentManagerState2();//為部門經理增加工作stateMachine.Dowork();}else{//如果請假天數在3天及其以內,就由項目經理做主審批后轉為結束狀態stateMachine.State = new AuditOverState2();stateMachine.Dowork();}}else{//項目經理不同意的話,也就不用提交給部門經理了,直接轉為審核結束狀態stateMachine.State = new AuditOverState2();stateMachine.Dowork();}//4-給申請人增加一個提示,讓他可以查看當前的最新審核結果}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 處理部門經理的審核(處理后對應審核結束狀態)/// </summary>internal class DepartmentManagerState2 : ILeaveRequestState{public void Dowork(StateMachine stateMachine){//1-先把業務模型創建出來LeaveRequestModel model = (LeaveRequestModel)stateMachine.BusinessModel;//模擬用戶處理界面Console.WriteLine("部門經理審核中,請稍后。。。");Console.WriteLine($"【{model?.User}】申請從【{model?.BeginDate}】開始請假【{model?.LeaveDays}】天,請審核(1:同意;2:不同意)");string? strInput = Console.ReadLine();if (!string.IsNullOrEmpty(strInput)){//設置會上下文中string result = "不同意";if ("1".Equals(strInput)){result = "同意";}model.AuditResult = result;}//2-業務處理,將審核結果保存到數據庫中//3-部門經理審核通過后,直接轉向審核結束狀態stateMachine.State = new AuditOverState2();stateMachine.Dowork();//4-給申請人增加一個提示,讓他可以查看當前的最新審核結果}}//Class_end
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace StatePattern.StateDemoThree
{/// <summary>/// 處理審核結束狀態/// </summary>internal class AuditOverState2 : ILeaveRequestState{public void Dowork(StateMachine stateMachine){//1-先把業務模型創建出來LeaveRequestModel model = (LeaveRequestModel)stateMachine.BusinessModel;//2-業務處理,在數據中記錄整個流程結束Console.WriteLine($"【{model.User}】你的請假申請流程審核結束,最終審核結果是【{model.AuditResult}】");}}//Class_end
}

? ?2.5.8、客戶端測試

using StatePattern.StateDemoThree;namespace StatePattern
{internal class Program{static void Main(string[] args){LeaveRequestTest();Console.ReadLine();}/// <summary>/// 請假流程審批/// </summary>private static void LeaveRequestTest(){//創建業務對象并設置業務數據StateDemoThree.LeaveRequestModel requestModel = new StateDemoThree.LeaveRequestModel();requestModel.User = "張三";requestModel.BeginDate = DateTime.Now.ToString("F");requestModel.LeaveDays = 5;//創建上下文對象StateDemoThree.LeaveRequestContext requestContext= new StateDemoThree.LeaveRequestContext();//為上下文設置業務對象模型requestContext.BusinessModel = requestModel;//配置上下文狀態requestContext.State = new ProjectManagerState2();//開始運行requestContext.Dowork();}}//Class_end 
}

? ?2.5.9、運行結果

三、項目源碼工程

kafeiweimei/Learning_DesignPattern: 這是一個關于C#語言編寫的基礎設計模式項目工程,方便學習理解常見的26種設計模式https://github.com/kafeiweimei/Learning_DesignPattern?tab=readme-ov-file

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88643.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88643.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88643.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python的婚紗影樓管理系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 隨著婚紗…

濾波電路Multisim電路仿真實驗匯總——硬件工程師筆記

目錄 1 濾波電路基礎知識 1.1 濾波電路的分類 1.1.1 按頻率選擇性分類 1.1.2 按實現方式分類 1.2 濾波電路的設計 1.2.1 確定濾波器類型 1.2.2 計算截止頻率 1.2.3 選擇濾波階數 1.2.4 考慮元件參數 1.2.5 仿真驗證 1.3 濾波電路的應用 1.3.1 電源濾波 1.3.2 音頻…

C++隨機打亂函數:簡化源碼與原理深度剖析

文章目錄一、Fisher-Yates洗牌算法核心原理二、std::random_shuffle簡化實現與缺陷分析簡化源碼&#xff08;核心邏輯&#xff09;原理層面的致命缺陷三、std::shuffle的現代改進與實現簡化源碼&#xff08;核心邏輯&#xff09;原理層面的關鍵改進四、隨機數生成器工作原理URB…

DBeaver連接MySQL8.0報錯Public Key Retrieval is not allowed

DBeaver 鏈接本地mysql8.0服務報錯Public Key Retrieval is not allowed為什么會出現這個錯誤&#xff1f;MySQL 8.0 默認使用新的認證插件&#xff1a;caching_sha2_password某些客戶端&#xff08;比如老版本的 JDBC 驅動或配置不當的 DBeaver&#xff09;在連接時&#xff0…

SpringBoot系列—統一功能處理(攔截器)

上篇文章&#xff1a; SpringBoot系列—MyBatis-plushttps://blog.csdn.net/sniper_fandc/article/details/148979284?fromshareblogdetail&sharetypeblogdetail&sharerId148979284&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目錄 1 攔…

《匯編語言:基于X86處理器》第7章 整數運算(3)

本章將介紹匯編語言最大的優勢之一:基本的二進制移位和循環移位技術。實際上&#xff0c;位操作是計算機圖形學、數據加密和硬件控制的固有部分。實現位操作的指令是功能強大的工具&#xff0c;但是高級語言只能實現其中的一部分&#xff0c;并且由于高級語言要求與平臺無關&am…

應用筆記|數字化儀在醫學SS-OCT中的應用

引言近些年來&#xff0c;OCT&#xff08;光學相干斷層掃描&#xff0c;Optical Coherence Tomography&#xff09;作為一種非破壞性3D光學成像技術逐漸在醫學眼科設備中流行起來。OCT可提供實時一維深度或二維截面或三維立體的圖像&#xff0c;分辨率可達微米&#xff08;μm&…

Ubuntu 22.04與24.04 LTS版本對比分析及2025年使用建議

Ubuntu 22.04與24.04 LTS版本對比分析及2025年使用建議 在2025年的技術環境下&#xff0c;Ubuntu 22.04和24.04 LTS各有優勢&#xff0c;選擇哪一個取決于具體應用場景和用戶需求。經過對系統內核、桌面環境、軟件生態、生命周期支持等多方面因素的綜合分析&#xff0c;本報告將…

Linux進程的生命周期:狀態定義、轉換與特殊場景

前言 在Linux系統中&#xff0c;進程是資源分配和調度的基本單位&#xff0c;而進程狀態則是理解進程行為的關鍵。從運行中的任務&#xff08;TASK_RUNNING&#xff09;到僵尸進程&#xff08;EXIT_ZOMBIE&#xff09;&#xff0c;每個狀態都反映了進程在內核調度、資源等待或父…

神經網絡簡介

大腦的基本計算單位是神經元&#xff08;neuron&#xff09;。人類的神經系統中大約有860億個神經元&#xff0c;它們被大約10^14-10^15個突觸&#xff08;synapses&#xff09;連接起來。下面圖表的左邊展示了一個生物學的神經元&#xff0c;右邊展示了一個常用的數學模型。每…

多路由協議融合與網絡服務配置實驗(電視機實驗)

多路由協議融合與網絡服務配置實驗文檔 一、實驗用途和意義 &#xff08;一&#xff09;用途 本實驗模擬企業復雜網絡環境&#xff0c;整合 OSPF、RIPv2 動態路由協議&#xff0c;結合 DHCP、FTP、Telnet 服務配置及訪問控制策略&#xff0c;實現多區域網絡互聯、服務部署與…

在指定conda 環境里安裝 jupyter 和 python kernel的方法

在 Conda 的指定環境中安裝 Jupyter 和 Python Kernel 是一個常見操作,以下是詳細步驟,確保在指定環境中正確配置 Jupyter 和 Python Kernel: 1. 準備工作 確保已安裝 Anaconda 或 Miniconda,Conda 環境管理工具可用。確認已創建或計劃使用的 Conda 環境。2. 步驟:安裝 J…

【數據結構與算法】數據結構初階:詳解順序表和鏈表(四)——單鏈表(下)

&#x1f525;個人主頁&#xff1a;艾莉絲努力練劍 ?專欄傳送門&#xff1a;《C語言》、《數據結構與算法》、C語言刷題12天IO強訓、LeetCode代碼強化刷題 &#x1f349;學習方向&#xff1a;C/C方向 ??人生格言&#xff1a;為天地立心&#xff0c;為生民立命&#xff0c;為…

Java+AI精準廣告革命:實時推送系統實戰指南

? 廣告推送的世紀難題 用戶反感&#xff1a;72%用戶因無關廣告卸載APP 轉化率低&#xff1a;傳統推送轉化率<0.5% 資源浪費&#xff1a;40%廣告預算被無效曝光消耗 &#x1f9e0; 智能廣告系統架構 &#x1f525; 核心模塊實現&#xff08;Java 17&#xff09; 1. 實時…

JVM組成及運行流程 - 面試筆記

JVM整體架構 JVM&#xff08;Java Virtual Machine&#xff09;是Java程序運行的核心環境&#xff0c;主要由以下幾個部分組成&#xff1a;1. 程序計數器&#xff08;Program Counter&#xff09; 特點&#xff1a;線程私有&#xff0c;每個線程都有獨立的程序計數器作用&#…

JavaEE——線程池

目錄前言1. 概念2. 線程池相關參數3. Executors的使用總結前言 線程是為了解決進程太重的問題&#xff0c;操作系統中進程的創建和銷毀需要較多的系統資源&#xff0c;用了輕量級的線程來代替部分線程&#xff0c;但是如果線程創建和銷毀的頻率也開始提升到了一定程度&#xf…

3 c++提高——STL常用容器(一)

目錄 1 string容器 1.1 string基本概念 1.2 string構造函數 1.3 string賦值操作 1.4 string字符串拼接 1.5 string查找和替換 1.6 string字符串比較 1.7 string字符存取 1.8 string插入和刪除 1.9 string子串 2 vector容器 2.1 vector基本概念 2.2 vector構造函數…

手把手教你用【Go】語言調用DeepSeek大模型

1、首先呢&#xff0c;點擊 “DeepSeek”” 這個&#xff0c; 可以充1塊玩玩。 2、然后獲取api-key 3、替換apiKey const (apiURL "https://api.deepseek.com/v1/chat/completions"apiKey "your api key" // 替換為你的實際 API KeymodelName &…

自動化UI測試工具TestComplete的核心功能及應用

對桌面應用穩定性與用戶體驗的挑戰&#xff0c;手動測試效率低、覆蓋有限&#xff0c;而普通自動化工具常難以應對復雜控件識別、腳本靈活性和大規模并行測試的需求。 自動化UI測試工具TestComplete憑借卓越的對象識別能力、靈活的測試創建方式以及高效的跨平臺并行執行功能&a…

【C/C++】邁出編譯第一步——預處理

【C/C】邁出編譯第一步——預處理 在C/C編譯流程中&#xff0c;預處理&#xff08;Preprocessing&#xff09;是第一個也是至關重要的階段。它負責對源代碼進行初步的文本替換與組織&#xff0c;使得編譯器在后續階段能正確地處理規范化的代碼。預處理過程不僅影響編譯效率&…