這篇文章給大家介紹怎么在C#項(xiàng)目中實(shí)現(xiàn)一個(gè)職責(zé)鏈模式,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

在軟件開(kāi)發(fā)中,我們通常會(huì)遇到一種場(chǎng)景,比如某個(gè)請(qǐng)求,會(huì)依次經(jīng)過(guò)系統(tǒng)中的很多個(gè)模塊來(lái)處理,如果某個(gè)模塊處理不了,則將請(qǐng)求傳遞給下一個(gè)模塊,比如在訂單處理中,首先要經(jīng)過(guò)用戶(hù)校驗(yàn),商品庫(kù)存充足校驗(yàn),如果不滿(mǎn)足條件,返回錯(cuò)誤,如果滿(mǎn)足條件才會(huì)到下一步處理。
在ASP.NET Core里有middleware中間鍵的概念,每一個(gè)請(qǐng)求進(jìn)來(lái),都會(huì)經(jīng)過(guò)一系列的Handler,這是一種職責(zé)鏈模式,每一個(gè)Handler都會(huì)決定是否處理該請(qǐng)求,以及是否決定將該請(qǐng)求傳遞給一下請(qǐng)求繼續(xù)處理。
在.NET的委托中,也有一個(gè)委托鏈概念,當(dāng)多個(gè)對(duì)象注冊(cè)同一事件時(shí),對(duì)象將委托放在一個(gè)鏈上,依次處理。
在JavaScript或者WPF的事件模型中,事件有冒泡和下沉,事件能夠逐個(gè)向上級(jí)或者下級(jí)對(duì)象傳遞,每個(gè)對(duì)象都會(huì)決定是否會(huì)對(duì)該事件進(jìn)行回應(yīng),或者終止事件的繼續(xù)傳遞。
這些都是典型的職責(zé)鏈模式,責(zé)任鏈模式為請(qǐng)求創(chuàng)建了一個(gè)接收者對(duì)象的鏈,每個(gè)接收者都包含對(duì)另一個(gè)接收者的引用。如果一個(gè)對(duì)象不能處理該請(qǐng)求,那么它會(huì)把相同的請(qǐng)求傳給下一個(gè)接收者,沿著這條鏈傳遞請(qǐng)求,直到有對(duì)象處理它為止。發(fā)出這個(gè)請(qǐng)求的客戶(hù)端并不知道鏈上的哪一個(gè)對(duì)象最終處理這個(gè)請(qǐng)求,這使得系統(tǒng)可以在不影響客戶(hù)端的情況下動(dòng)態(tài)地重新組織和分配責(zé)任。
假設(shè)在一個(gè)電腦游戲中,每個(gè)角色都有兩個(gè)屬性:攻擊值和防御值。
public class Creature
{
public string Name;
public int Attack, Defense;
public Creature(string name, int attack, int defense)
{
Name = name;
Attack = attack;
Defense = defense;
}
public override string ToString()
{
return $"Name:{Name} Attack:{Attack} Defense:{Defense}";
}
}現(xiàn)在這個(gè)角色會(huì)在游戲中進(jìn)行活動(dòng),他可能會(huì)撿到一些武器增加自己的攻擊值或者防御值。我們通過(guò)CreatureModifer來(lái)修改該對(duì)象的攻擊值或者防御值。通常,在游戲中會(huì)有多個(gè)修改器會(huì)對(duì)同一角色進(jìn)行修改,比如撿到武器A,然后撿到武器B等等,因此我們可以將這些修改器按照順序附加到Creature對(duì)象上進(jìn)行逐個(gè)修改。
在經(jīng)典的職責(zé)鏈實(shí)現(xiàn)模式中,可以向下面這種方式來(lái)定義CreatureModifier對(duì)象:
public class CreatureModifier
{
protected Creature creature;
protected CreatureModifier next;
public CreatureModifier(Creature creature)
{
this.creature = creature;
}
public void Add(CreatureModifier m)
{
if (next != null)
{
next.Add(m);
}
else
{
next = m;
}
}
public virtual void Handle()
{
next?.Handle();
}
}在這個(gè)類(lèi)中:
構(gòu)造函數(shù)里保存對(duì)待修改對(duì)象Creature的引用。
該類(lèi)沒(méi)有做多少工作,但他不是抽象類(lèi),其他類(lèi)可以繼承該對(duì)象。
Add方法可以添加其他CreatureModifier類(lèi)到處理鏈條上。如果當(dāng)前修改對(duì)象next對(duì)象為空,則賦值,否則將他添加到處理鏈的末端。
Handle方法簡(jiǎn)單調(diào)用下個(gè)處理鏈上對(duì)象的Handle方法。子類(lèi)可以重寫(xiě)該方法以實(shí)現(xiàn)具體的操作。
現(xiàn)在,可以定義一個(gè)具體的修改類(lèi)了,這個(gè)類(lèi)可以將角色的攻擊值翻倍。
public class DoubleAttackModifier : CreatureModifier
{
public DoubleAttackModifier(Creature c) : base(c)
{
}
public override void Handle()
{
creature.Attack *= 2;
Console.WriteLine($"Doubling {creature.Name}'s attack,Attack:{creature.Attack},Defense:{creature.Defense}");
base.Handle();
}
}該類(lèi)繼承自CreatureModifier類(lèi),并重寫(xiě)了Handle方法,在方法里做了兩件事,一是將Attack屬性翻倍,另外一個(gè)非常重要,就是調(diào)用了基類(lèi)的Handle方法,讓職責(zé)鏈上的修改器繼續(xù)進(jìn)行下去。千萬(wàn)不要忘記調(diào)用,否則鏈條在這里就會(huì)終止了,不會(huì)繼續(xù)往下傳遞了。
接著,新建一個(gè)增加防御值的修改器,如果攻擊值小于2,則防御值增加1:
public class IncreaseDefenseModifier : CreatureModifier
{
public IncreaseDefenseModifier(Creature creature) : base(creature)
{
}
public override void Handle()
{
if (creature.Attack <= 2)
{
Console.WriteLine($"Increasing {creature.Name}'s defense");
creature.Defense++;
}
base.Handle();
}
}現(xiàn)在整個(gè)應(yīng)用代碼如下:
Creature creature = new Creature("yy", 1, 1);
Console.WriteLine(creature);
CreatureModifier modi = new CreatureModifier(creature);
modi.Add(new DoubleAttackModifier(creature));//attack 2,defense 1
modi.Add(new DoubleAttackModifier(creature));//attack 4,defense 1
modi.Add(new IncreaseDefenseModifier(creature));//attack 4,defense 1
modi.Handle();可以看到,第三個(gè)IncreaseDefenseModifier因?yàn)椴粷M(mǎn)足attack小于等于2的條件,所以Defense沒(méi)有修改。
下面這個(gè)例子來(lái)自 /tupian/20230522/ ,首先定義一個(gè)包含用來(lái)建立處理鏈的方法,也定義一個(gè)處理請(qǐng)求的方法:
public interface IHandle
{
IHandle SetNext(IHandle handle);
object Handle(object request);
}再定義一個(gè)抽象類(lèi),用來(lái)設(shè)置職責(zé)鏈和處理職責(zé)鏈上的請(qǐng)求。
public abstract class AbstractHandle : IHandle
{
private IHandle _nextHandle;
public IHandle SetNext(IHandle handle)
{
this._nextHandle = handle;
return handle;
}
public virtual object Handle(object request)
{
if (this._nextHandle != null)
{
return this._nextHandle.Handle(request);
}
else
{
return null;
}
}
}在定義幾個(gè)具體的職責(zé)鏈上處理的具體類(lèi):
public class MonkeyHandle : AbstractHandle
{
public override object Handle(object request)
{
if (request.ToString() == "Banana")
{
return $"Monkey: I'll eat the {request.ToString()}.\n";
}
else
{
return base.Handle(request);
}
}
}
public class SquirrelHandler : AbstractHandle
{
public override object Handle(object request)
{
if (request.ToString() == "Nut")
{
return $"Squirrel: I'll eat the {request.ToString()}.\n";
}
else
{
return base.Handle(request);
}
}
}
public class DogHandler : AbstractHandle
{
public override object Handle(object request)
{
if (request.ToString() == "MeatBall")
{
return $"Dog: I'll eat the {request.ToString()}.\n";
}
else
{
return base.Handle(request);
}
}
}再定義使用方法,參數(shù)為單個(gè)職責(zé)鏈參數(shù):
public static void ClientCode(AbstractHandler handler)
{
foreach (var food in new List<string> { "Nut", "Banana", "Cup of coffee" })
{
Console.WriteLine($"Client: Who wants a {food}?");
var result = handler.Handle(food);
if (result != null)
{
Console.Write($" {result}");
}
else
{
Console.WriteLine($" {food} was left untouched.");
}
}
}現(xiàn)在定義流程處理鏈:
// The other part of the client code constructs the actual chain.
var monkey = new MonkeyHandler();
var squirrel = new SquirrelHandler();
var dog = new DogHandler();
monkey.SetNext(squirrel).SetNext(dog);
// The client should be able to send a request to any handler, not
// just the first one in the chain.
Console.WriteLine("Chain: Monkey > Squirrel > Dog\n");
ClientCode(monkey);
Console.WriteLine();
Console.WriteLine("Subchain: Squirrel > Dog\n");
ClientCode(squirrel);輸出結(jié)果為:
Chain: Monkey > Squirrel > Dog
Client: Who wants a Nut?
Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
Monkey: I'll eat the Banana.
Client: Who wants a Cup of coffee?
Cup of coffee was left untouched.Subchain: Squirrel > Dog
Client: Who wants a Nut?
Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
Banana was left untouched.
Client: Who wants a Cup of coffee?
Cup of coffee was left untouched.
職責(zé)鏈模式是一個(gè)很簡(jiǎn)單的設(shè)計(jì)模式,在需要順序處理請(qǐng)求比如命令或查詢(xún)時(shí),可以使用該模式。最簡(jiǎn)單的實(shí)現(xiàn)方式就是每個(gè)對(duì)象引用下一個(gè)待處理的對(duì)象,可以使用一個(gè)List或者LinkList來(lái)實(shí)現(xiàn)。
關(guān)于怎么在C#項(xiàng)目中實(shí)現(xiàn)一個(gè)職責(zé)鏈模式就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
分享名稱(chēng):怎么在C#項(xiàng)目中實(shí)現(xiàn)一個(gè)職責(zé)鏈模式-創(chuàng)新互聯(lián)
分享地址:http://chinadenli.net/article6/cogpig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、響應(yīng)式網(wǎng)站、定制網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司、搜索引擎優(yōu)化、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容