怎么在C#项目中实现一个职责链模式

发布时间:2020-12-21 15:03:21 作者:Leah
来源:亿速云 阅读:158

这篇文章给大家介绍怎么在C#项目中实现一个职责链模式,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

前言

    在软件开发中,我们通常会遇到一种场景,比如某个请求,会依次经过系统中的很多个模块来处理,如果某个模块处理不了,则将请求传递给下一个模块,比如在订单处理中,首先要经过用户校验,商品库存充足校验,如果不满足条件,返回错误,如果满足条件才会到下一步处理。

    在ASP.NET Core里有middleware中间键的概念,每一个请求进来,都会经过一系列的Handler,这是一种职责链模式,每一个Handler都会决定是否处理该请求,以及是否决定将该请求传递给一下请求继续处理。

    在.NET的委托中,也有一个委托链概念,当多个对象注册同一事件时,对象将委托放在一个链上,依次处理。

    在JavaScript或者WPF的事件模型中,事件有冒泡和下沉,事件能够逐个向上级或者下级对象传递,每个对象都会决定是否会对该事件进行回应,或者终止事件的继续传递。

    这些都是典型的职责链模式,责任链模式为请求创建了一个接收者对象的链,每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,沿着这条链传递请求,直到有对象处理它为止。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

示例1

假设在一个电脑游戏中,每个角色都有两个属性:攻击值和防御值。

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}";
 }
}

     现在这个角色会在游戏中进行活动,他可能会捡到一些武器增加自己的攻击值或者防御值。我们通过CreatureModifer来修改该对象的攻击值或者防御值。通常,在游戏中会有多个修改器会对同一角色进行修改,比如捡到武器A,然后捡到武器B等等,因此我们可以将这些修改器按照顺序附加到Creature对象上进行逐个修改。

    在经典的职责链实现模式中,可以向下面这种方式来定义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();
 }
}

    在这个类中:

    现在,可以定义一个具体的修改类了,这个类可以将角色的攻击值翻倍。

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属性翻倍,另外一个非常重要,就是调用了基类的Handle方法,让职责链上的修改器继续进行下去。千万不要忘记调用,否则链条在这里就会终止了,不会继续往下传递了。

     接着,新建一个增加防御值的修改器,如果攻击值小于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();
 }
}

     现在整个应用代码如下:

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没有修改。

示例2

    下面这个例子来自 https://refactoring.guru/ ,首先定义一个包含用来建立处理链的方法,也定义一个处理请求的方法:

public interface IHandle
{
 IHandle SetNext(IHandle handle);
 object Handle(object request);
}

     再定义一个抽象类,用来设置职责链和处理职责链上的请求。

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);
 }
 }
}

    再定义使用方法,参数为单个职责链参数:

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.");
 }
 }
}

     现在定义流程处理链:

// 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);

    输出结果为:

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.

总结

    职责链模式是一个很简单的设计模式,在需要顺序处理请求比如命令或查询时,可以使用该模式。最简单的实现方式就是每个对象引用下一个待处理的对象,可以使用一个List或者LinkList来实现。

关于怎么在C#项目中实现一个职责链模式就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. 怎么在vue2.0项目中使用swiper组件实现一个轮播效果
  2. 怎么在C#项目中获取App.Config配置项

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

目中

上一篇:EL表达式如何在jsp项目中使用

下一篇:Java中责任链模式的作用有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》