如何使用C#在命令模式中的命令之间共享相同的上下文?
我已经在我的应用程序中实现了命令模式(以多支持的方式) 结构:如何使用C#在命令模式中的命令之间共享相同的上下文?,c#,design-patterns,command-pattern,C#,Design Patterns,Command Pattern,我已经在我的应用程序中实现了命令模式(以多支持的方式) 结构: class MultiCommand : BaseCommand abstract class BaseCommand : ICommand 工艺流程: var commandsGroup = new MultiCommand(new List<ICommand>() { new Command1(), new Comman
class MultiCommand : BaseCommand
abstract class BaseCommand : ICommand
工艺流程:
var commandsGroup = new MultiCommand(new List<ICommand>()
{
new Command1(),
new Command2(),
new Command3(),
});
commandsGroup.Execute()
IServerController
的实例化将在MultiCommand Group
初始化之前进行
如何为组中的所有命令创建这样的共享上下文
上下文类的示例:
public class CommandContext
{
public IServerController ServerController;
public RequiredData Data { get; set; }
public CommandContext(){}
}
重要
最小的实现代码是您可以在
BaseCommand
类(及其派生类)上有一个构造函数,该构造函数将接受某种类型的上下文
类。当实例化将属于同一组的命令时,可以为它们提供所有相同的上下文对象。可能是这样的:
public class CommandContext
{
// The object that will be the target of the commands' actions.
public object Data { get; set; }
// ... any other properties that might be useful as shared state between commands...
}
public abstract class BaseCommand : ICommand
{
protected CommandContext Context { get; private set; }
public BaseCommand(CommandContext ctx)
{
Context = ctx;
}
}
public class ChangeSomethingIDCommand : BaseCommand
{
public ChangeSomethingIDCommand(CommandContext ctx) : base(ctx)
{ }
public void Execute()
{
var target = (SomeDomainClass)Context.Data;
target.SomethingID++;
}
}
// Elsewhere in your code (assuming 'myTargetDomainClassInstance' is
// a SomeDomainClass instance that has been instantiated elsewhere and
// represents the object upon which the commands will do work):
var ctx = new CommandContext { Data = myTargetDomainClassInstance };
var commandGroup = new MultiItemCommand(ctx, new List<ICommand>
{
new ChangeSomethingIDCommand(ctx),
new Command2(ctx),
new Command3(ctx)
});
commandGroup.Execute();
公共类CommandContext
{
//将成为命令操作目标的对象。
公共对象数据{get;set;}
//…作为命令之间的共享状态可能有用的任何其他属性。。。
}
公共抽象类BaseCommand:ICommand
{
受保护的CommandContext上下文{get;private set;}
公共BaseCommand(CommandContext ctx)
{
上下文=ctx;
}
}
公共类ChangeSomethingIDCommand:BaseCommand
{
公共ChangeSomethingIDCommand(CommandContext ctx):基本(ctx)
{ }
public void Execute()
{
var target=(SomeDomainClass)Context.Data;
target.SomethingID++;
}
}
//代码中的其他位置(假设“myTargetDomainClassInstance”为
//已在其他位置实例化的SomeDomainClass实例,以及
//表示命令将在其上工作的对象):
var ctx=newcommandcontext{Data=myTargetDomainClassInstance};
var commandGroup=新的多项目命令(ctx,新列表
{
新的ChangeSomethingIDCommand(ctx),
新命令2(ctx),
新命令3(ctx)
});
commandGroup.Execute();
我建议做一些通用的东西。下面是一个超级简单的例子
class MultiCommand<TContext>
{
List<Command<TContext>> Commands;
TContext Context;
}
类多命令
{
列出命令;
t语境;
}
1)如果要保留此接口,则必须将此上下文作为构造函数参数传递:
新的多命令(新列表()
{
新命令1(上下文),
新命令2(上下文),
新命令3(上下文),
})
2) 作为另一个选项,您可以接受委托列表而不是命令列表。
多命令将如下所示:
类多命令:ICommand
{
公共多命令(列表命令、上下文)
}
这几乎是一样的,只是多命令负责所有共享相同上下文的命令
3) 看起来多命令中的命令取决于上一个命令的结果。在这种情况下,命令模式可能不是最好的。也许您应该尝试在这里实现中间件链
接口imidware
{
无效运行(TContext上下文);
}
类链
{
私有列表处理程序;
无效登记簿(IMIDLEWARE m);
公共无效运行(TContext上下文)
{
ForEach(h=>h.Run(context));
}
}
那么如何改变你的方法呢?我最近为DDD做了一个架构,并执行了一个commad暗示原子操作(从persistence检索聚合根,应用域规则并对聚合进行排序),因此我不需要共享上下文,可以毫无顾虑地批处理多个命令
您有一个cqrs体系结构,它使用命令模式和我发布的上述策略。My 0.02:
1) 多命令类看起来像一个
您可能希望在基本命令类中添加一个GetParentCommand()方法,并在多命令类中添加一个AddChildCommand()方法,该方法设置每个子命令的父命令
然后子命令可以从其父对象获取上下文对象。(上下文对象也应该在基类中定义。它可能是泛型类型。)
编辑:
另一个选项是将上下文对象作为Execute函数的参数:
class MultiCommand : BaseCommand
{
void Execute(CommandContext context)
{
Children.Execute(context);
}
}
考虑功能性风格
public class SomeMainClass{
public void MultiCommandInit()
{
MultiCommand.New()
.Add(new Command1())
.Add(new Command2())
.Add(new Command3())
.SharedContext(CC => {
CC.Data = new RequiredData();
CC.ServerController = GetServerController();
});
}
private IServerController GetServerController()
{
// return proper instance of server controller
throw new NotImplementedException();
}
}
需要此扩展方法/函数
public static class XMultiCommand
{
// How can I have a shared context like this for all Commands of the group?
public static MultiCommand SharedContext(this MultiCommand mc, Action<CommandContext> CallBack)
{
var cc = new CommandContext();
CallBack(cc);
mc.SharedContext = cc;
return mc;
}
}
公共静态类xmulti命令
{
//如何为组中的所有命令提供这样的共享上下文?
公共静态多命令SharedContext(此多命令mc,操作回调)
{
var cc=new CommandContext();
回调(cc);
mc.SharedContext=cc;
返回mc;
}
}
最后,这些对多命令的更改
public class MultiCommand
{
private System.Collections.Generic.List<ICommand> list;
public List<ICommand> Commands { get { return list; } }
public CommandContext SharedContext { get; set; }
public MultiCommand() { }
public MultiCommand(System.Collections.Generic.List<ICommand> list)
{
this.list = list;
}
public MultiCommand Add(ICommand cc)
{
list.Add(cc);
return this;
}
internal void Execute()
{
throw new NotImplementedException();
}
public static MultiCommand New()
{
return new MultiCommand();
}
}
公共类多命令
{
private System.Collections.Generic.List列表;
公共列表命令{get{return List;}}
公共命令上下文共享上下文{get;set;}
公共多命令(){}
公共多命令(System.Collections.Generic.List)
{
this.list=列表;
}
公共多命令添加(ICommand cc)
{
列表。添加(cc);
归还这个;
}
内部void Execute()
{
抛出新的NotImplementedException();
}
公共静态多命令New()
{
返回新的多命令();
}
}
使用功能性风格会发生很酷的事情
class MultiCommand : BaseCommand
{
void Execute(CommandContext context)
{
Children.Execute(context);
}
}
public class SomeMainClass{
public void MultiCommandInit()
{
MultiCommand.New()
.Add(new Command1())
.Add(new Command2())
.Add(new Command3())
.SharedContext(CC => {
CC.Data = new RequiredData();
CC.ServerController = GetServerController();
});
}
private IServerController GetServerController()
{
// return proper instance of server controller
throw new NotImplementedException();
}
}
public static class XMultiCommand
{
// How can I have a shared context like this for all Commands of the group?
public static MultiCommand SharedContext(this MultiCommand mc, Action<CommandContext> CallBack)
{
var cc = new CommandContext();
CallBack(cc);
mc.SharedContext = cc;
return mc;
}
}
public class MultiCommand
{
private System.Collections.Generic.List<ICommand> list;
public List<ICommand> Commands { get { return list; } }
public CommandContext SharedContext { get; set; }
public MultiCommand() { }
public MultiCommand(System.Collections.Generic.List<ICommand> list)
{
this.list = list;
}
public MultiCommand Add(ICommand cc)
{
list.Add(cc);
return this;
}
internal void Execute()
{
throw new NotImplementedException();
}
public static MultiCommand New()
{
return new MultiCommand();
}
}
public class Command1: BaseCommand
{
//inject as parameter instead
public void Execute(Context ctx)
{
}
}