您好,登錄后才能下訂單哦!
這篇文章給大家介紹怎么在C#項目中實現(xiàn)一個職責鏈模式,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
在軟件開發(fā)中,我們通常會遇到一種場景,比如某個請求,會依次經(jīng)過系統(tǒng)中的很多個模塊來處理,如果某個模塊處理不了,則將請求傳遞給下一個模塊,比如在訂單處理中,首先要經(jīng)過用戶校驗,商品庫存充足校驗,如果不滿足條件,返回錯誤,如果滿足條件才會到下一步處理。
在ASP.NET Core里有middleware中間鍵的概念,每一個請求進來,都會經(jīng)過一系列的Handler,這是一種職責鏈模式,每一個Handler都會決定是否處理該請求,以及是否決定將該請求傳遞給一下請求繼續(xù)處理。
在.NET的委托中,也有一個委托鏈概念,當多個對象注冊同一事件時,對象將委托放在一個鏈上,依次處理。
在JavaScript或者WPF的事件模型中,事件有冒泡和下沉,事件能夠逐個向上級或者下級對象傳遞,每個對象都會決定是否會對該事件進行回應(yīng),或者終止事件的繼續(xù)傳遞。
這些都是典型的職責鏈模式,責任鏈模式為請求創(chuàng)建了一個接收者對象的鏈,每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,沿著這條鏈傳遞請求,直到有對象處理它為止。發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織和分配責任。
假設(shè)在一個電腦游戲中,每個角色都有兩個屬性:攻擊值和防御值。
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)在這個角色會在游戲中進行活動,他可能會撿到一些武器增加自己的攻擊值或者防御值。我們通過CreatureModifer來修改該對象的攻擊值或者防御值。通常,在游戲中會有多個修改器會對同一角色進行修改,比如撿到武器A,然后撿到武器B等等,因此我們可以將這些修改器按照順序附加到Creature對象上進行逐個修改。
在經(jīng)典的職責鏈實現(xiàn)模式中,可以向下面這種方式來定義CreatureModifier對象:
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òu)造函數(shù)里保存對待修改對象Creature的引用。
該類沒有做多少工作,但他不是抽象類,其他類可以繼承該對象。
Add方法可以添加其他CreatureModifier類到處理鏈條上。如果當前修改對象next對象為空,則賦值,否則將他添加到處理鏈的末端。
Handle方法簡單調(diào)用下個處理鏈上對象的Handle方法。子類可以重寫該方法以實現(xiàn)具體的操作。
現(xiàn)在,可以定義一個具體的修改類了,這個類可以將角色的攻擊值翻倍。
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(); } }
該類繼承自CreatureModifier類,并重寫了Handle方法,在方法里做了兩件事,一是將Attack屬性翻倍,另外一個非常重要,就是調(diào)用了基類的Handle方法,讓職責鏈上的修改器繼續(xù)進行下去。千萬不要忘記調(diào)用,否則鏈條在這里就會終止了,不會繼續(xù)往下傳遞了。
接著,新建一個增加防御值的修改器,如果攻擊值小于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)在整個應(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();
可以看到,第三個IncreaseDefenseModifier因為不滿足attack小于等于2的條件,所以Defense沒有修改。
下面這個例子來自 https://refactoring.guru/ ,首先定義一個包含用來建立處理鏈的方法,也定義一個處理請求的方法:
public interface IHandle { IHandle SetNext(IHandle handle); object Handle(object request); }
再定義一個抽象類,用來設(shè)置職責鏈和處理職責鏈上的請求。
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; } } }
在定義幾個具體的職責鏈上處理的具體類:
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ù)為單個職責鏈參數(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.
職責鏈模式是一個很簡單的設(shè)計模式,在需要順序處理請求比如命令或查詢時,可以使用該模式。最簡單的實現(xiàn)方式就是每個對象引用下一個待處理的對象,可以使用一個List或者LinkList來實現(xiàn)。
關(guān)于怎么在C#項目中實現(xiàn)一個職責鏈模式就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。