当前的实现几乎与简单的策略设计模式一致。有多个步骤要执行,这些步骤将由以下界面调用:
public interface ICommandStep
{
void Execute(CommandParameters cParams);
string StepName { get; }
}
示例实现者:
public class Step1 : ICommandStep {
public string StepName => "Initial Step";
public void Execute(CommandParameters cParams) {
// instructions
}
}
到目前为止,有很多不同的类实现了这个接口,我想确保所有这些类都有一个执行前后步骤。例如log state,params,StepName start和end。
我如何介绍一种方法,使protected virtual void PreExecute
和protected virtual void PostExecute
方法具有通用(可覆盖)逻辑,并确保始终按此顺序调用该方法:
1. PreExecute
2. Execute
3. PostExecute
最好不要在实现者类中更改Execute方法。
可以引入抽象类。
答案 0 :(得分:3)
您可以按所需顺序声明基类并定义可覆盖的方法:
public interface ICommandStep
{
void Execute(CommandParameters cParams);
string StepName { get; }
}
public abstract class CommandBase : ICommandStep
{
public void Execute(CommandParameters cParams)
{
PreExecute();
ExecuteInternal(cParams);
PostExecute();
}
protected virtual void PostExecute()
{
}
protected virtual void ExecuteInternal(CommandParameters cParams)
{
}
protected virtual void PreExecute()
{
}
public abstract string StepName { get; }
}
public class Step1 : CommandBase
{
public override string StepName => "Initial Step";
protected override void ExecuteInternal(object cParams)
{
// instructions
}
}
答案 1 :(得分:0)
向界面添加新方法必然意味着打破现有的实现。如果实现是可选的,那么您应该使用abstract
类而不是interface
。
通过添加新接口并在扩展方法中添加运行时类型检查,存在另一种选择,如下所示:
public interface ICommandStep
{
void Execute(CommandParameters cParams);
string StepName { get; }
}
public interface ICommandStep2 : ICommandStep
{
void PreExecute()
void PostExecute()
}
public static class Extensions
{
public static void Execute2(this ICommandStep step, CommandParameters cParams)
{
if( step is ICommandStep2 step2 )
{
step2.PreExecute();
step2.Execute( cParams );
step2.PostExecute();
}
else
{
step2.Execute( cParams );
}
}
}
用法:
ICommandStep[] steps = ...
foreach( ICommandStep step in steps )
{
step.Execute2( cmdParams );
}
答案 2 :(得分:0)
我可以想到2个解决方案:
2。:
的示例实现using System;
namespace ConsoleApplication6
{
/// <summary>
/// This is the component in Decorator Pattern
/// </summary>
public interface ICommandStep
{
void Execute(String cParams);
string StepName { get; }
}
/// <summary>
/// This is the concrete component in Decorator Pattern
/// </summary>
public class ConcreteStep1 : ICommandStep
{
public string StepName
{
get
{
return "1";
}
}
public void Execute(string cParams)
{
Console.WriteLine($"STEP {StepName}: EXECUTE");
}
}
/// <summary>
/// This is the decorator in Decorator Pattern
/// </summary>
public abstract class StepDecorator : ICommandStep
{
protected ICommandStep _commandStep;
public abstract string StepName
{
get;
}
public StepDecorator(ICommandStep commandStep)
{
this._commandStep = commandStep;
}
public abstract void Execute(string cParams);
}
/// <summary>
/// This is the concrete decorator in Decorator Pattern
/// </summary>
public class ConcreteStepDecorator : StepDecorator
{
public ConcreteStepDecorator(ICommandStep commandStep) : base(commandStep) { }
public override string StepName
{
get
{
return _commandStep.StepName;
}
}
public override void Execute(string cParams)
{
// You can do whatever you want before / after execution of command
Console.WriteLine($"STEP {_commandStep.StepName}: PRE EXECUTE");
_commandStep.Execute(cParams);
Console.WriteLine($"STEP {_commandStep.StepName}: POST EXECUTE");
}
}
/// <summary>
/// This is a Simple Factory. You encapsulate here creation of ICommandStep, so that it will always be decorated
/// </summary>
public class SimpleStepFactory
{
public ICommandStep createStep()
{
return new ConcreteStepDecorator(new ConcreteStep1());
}
}
class Program
{
static void Main(string[] args)
{
var step = new SimpleStepFactory().createStep();
step.Execute("params");
Console.ReadLine();
}
}
}
此解决方案有几个优点: