首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >继承、命令和事件来源

继承、命令和事件来源
EN

Software Engineering用户
提问于 2012-08-29 14:55:16
回答 2查看 1.6K关注 0票数 5

为了不重复几次,我想分解一些常见的东西。例如,假设我们有一头牛和一匹马。牛产奶,马跑得快,但两者都吃草。

代码语言:javascript
复制
public class Herbivorous
{
   protected int Quantity;

   public void EatGrass(int quantity)
   {
      var evt= Build.GrassEaten
                    .WithQuantity(quantity);
      RaiseEvent(evt);
   }

   public void Apply(GrassEaten evt)
   {
       _quantity= evt.Quantity;
   }
}

public class Horse : Herbivorous
{
   private bool _HasFastRun;

   public void RunFast()
   {
      var evt= Build.FastRun;
      RaiseEvent(evt);
   }

   public void Apply(FastRunevt)
   {
       _HasFastRun= true;
   }
}

public class Cow: Herbivorous
{
   private bool _IsMilkProduced;

   public void ProduceMilk()
   {
      var evt= Build.MilkProduced;
      RaiseEvent(evt);
   }

   public void Apply(MilkProduced evt)
   {
       _IsMilkProduced= true;
   }
}

要吃草,我的应用程序接收Json或xml中的命令,或者任何反序列化到该类中的命令:

代码语言:javascript
复制
namespace Herbivorous
{
   public class EatGrass : CommandBase
   {
      public Guid IdHerbivorous {get; set;}
      public Guid CommitId {get; set;}
      public long Version {get; set;}
      public int Quantity {get; set;}
   }
}

命令处理程序应该是:

代码语言:javascript
复制
public class EatGrassHandler : CommandHandler<EatGrass>
{
   public override CommandValidation Execute(EatGrass cmd)
   {
      Contract.Requires<ArgumentNullException>(cmd != null);
      Herbivorous herbivorous= EventRepository.GetById<Herbivorous>(cmd.Id);
      if (herbivorous.IsNull())
         throw new AggregateRootInstanceNotFoundException();
      herbivorous.EatGrass(cmd.Quantity);
      EventRepository.Save(herbivorous, cmd.CommitId);
   }
}

到目前一切尚好。我有一个食草动物对象,我可以访问它的EatGrass函数,不管它是马还是牛,都不重要。唯一的问题是:

代码语言:javascript
复制
EventRepository.GetById<Herbivorous>(cmd.Id)

事实上,让我们想象一下,我们有一头奶牛,它在早上产奶,现在想吃草。EventRepository包含一个事件MilkProduced,然后是命令EatGrass。有了CommandHandler,我们就不再是在奶牛面前了,食草者对产奶一无所知。它应该做些什么?

我是否应该有明确的上下文命令,比如:

代码语言:javascript
复制
namespace Herbivorous.Cow
    {
       public class EatGrass : CommandBase
       {
          public Guid IdHerbivorous {get; set;}
          public Guid CommitId {get; set;}
          public long Version {get; set;}
          public int Quantity {get; set;}
       }
       public class ProduceMilk : CommandBase
       {
          public Guid IdHerbivorous {get; set;}
          public Guid CommitId {get; set;}
          public long Version {get; set;}
       }
    }

这意味着,要求我的食草动物吃草的外部成分应该知道,在这种有限的范围内,我们谈论的是一头牛。在前一个命令中,我们讨论的是一种一般的食草动物行为,所以我电话的上下文并不重要。我们知道我们需要食草动物来吃草,仅此而已。

这是我的主要问题,可能是特定域从一个有界上下文泄漏到另一个上下文。实际上,这也可能意味着,在处理多个应用程序之间的接口时,我不能支持抽象。我想知道..。

或者当我重建我的食草动物时,我可以接受任何事情。这意味着,如果它找不到一个方法来应用这个事件,他将很好地尝试应用它的下一个流。这是真正的简单解决方案,但它并不能让我轻松地知道,事件可能不会被应用(并且不会产生错误)时,我的对象。(实际上,我想得越多,就越不觉得内疚。)

谢谢你的帮助,我才刚刚开始处理这类问题,我很高兴从更有经验的人那里得到一些消息。

EN

回答 2

Software Engineering用户

发布于 2012-08-29 15:20:51

首先,将一个虚拟方法Execute(cmd)添加到您的Herbivorous中,并将用于将命令分派到那里的命令方法的代码放在那里。然后,Herbivorous的每个子类都可以覆盖该方法,并支持子类特有的所有命令方法。看起来应该是这样:

代码语言:javascript
复制
public class Cow: Herbivorous
{
   public override void Execute(Command cmd)
   {
      if(cmd is ProduceMilkCommand)
          ProduceMilk(cmd);  // execute specific command
      else
          base.Execute(cmd); // delegate general commands to the base class
   }
}

为了从给定的命令中创建一个新的对象,将一个System.Type字段添加到您的cmd中,并使用反射来创建特定的Herbivorous子类型的实例。或者使用原型模式创建一个新实例(您的命令必须存储对该原型对象的引用)。第三种选择是使用抽象工厂模式,然后命令必须存储对正确工厂子类型的引用。

当然,如果您已经向我们展示了命令类当前的样子以及命令是如何创建的,我想我可以给您一个更好的答案。在代码片段中使用"var“命令隐藏了一些细节,这些细节对于一个更精确的答案可能很重要。

票数 1
EN

Software Engineering用户

发布于 2013-08-14 04:01:20

对于你的食草动物类来说,跳过不懂的事情是可以的。

我在这条线中学到了很多关于这个和相关问题的知识。

希望这能帮上忙。我真希望我的地盘里有牛和马!

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/162830

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档