C# 介绍;“强制性”;接口实现者的方法

C# 介绍;“强制性”;接口实现者的方法,c#,oop,design-patterns,interface,C#,Oop,Design Patterns,Interface,当前的实现与一个简单的策略设计模式非常一致。需要执行多个步骤,这些步骤将由以下接口调用: public interface ICommandStep { void Execute(CommandParameters cParams); string StepName { get; } } 示例实现者: public class Step1 : ICommandStep { public string StepName => "Initial Step";

当前的实现与一个简单的策略设计模式非常一致。需要执行多个步骤,这些步骤将由以下接口调用:

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
    }
}
到目前为止,有许多不同的类实现了这个接口,我想确保它们都有一个执行前和执行后的步骤。例如,日志状态、参数、步骤名开始和结束

我如何介绍一种方法,使用公共(可重写)逻辑使
受保护的virtual void PreExecute
受保护的virtual void PostExecute
方法,并确保始终按以下顺序调用该方法:

1. PreExecute
2. Execute
3. PostExecute
最好不改变实现器类中的Execute方法


引入抽象类是可能的。

您可以按照需要的顺序声明基类并定义可重写的方法:

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

向接口添加新方法必然意味着破坏现有的实现。如果实现是可选的,那么应该使用
抽象
类而不是
接口

另一种方法是添加新接口并在扩展方法中添加运行时类型检查,如下所示:

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

我可以想出两种解决方案:

  • Backs提出的模板方法模式
  • 和工厂一起装饰图案。当您想在调用其他对象之前/之后执行一些代码时,Decorator模式非常有用。工厂是为了确保每个创建的对象都将被装饰
  • 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();
            }
        }
    }
    
    使用系统;
    命名空间控制台应用程序6
    {
    /// 
    ///这是Decorator模式中的组件
    /// 
    公共接口ICommandStep
    {
    无效执行(字符串cparam);
    字符串步骤名{get;}
    }
    /// 
    ///这是Decorator模式中的具体组件
    /// 
    公共类具体步骤1:ICommandStep
    {
    公共字符串步骤名
    {
    得到
    {
    返回“1”;
    }
    }
    public void Execute(字符串cParams)
    {
    WriteLine($“步骤{StepName}:EXECUTE”);
    }
    }
    /// 
    ///这是decorator模式中的decorator
    /// 
    公共抽象类StepDecorator:ICommandStep
    {
    受保护的ICommandStep\u commandStep;
    公共抽象字符串步骤名
    {
    得到;
    }
    公共步骤装饰器(ICommandStep命令步骤)
    {
    这个._commandStep=commandStep;
    }
    公共抽象void Execute(字符串cparam);
    }
    /// 
    ///这是decorator模式中的具体decorator
    /// 
    公共类ConcreteStepDecorator:StepDecorator
    {
    公共ConcreteStepDecorator(ICommandStepCommandStep):基(commandStep){}
    公共重写字符串StepName
    {
    得到
    {
    返回_commandStep.StepName;
    }
    }
    公共重写无效执行(字符串CPARAM)
    {
    //在执行命令之前/之后,您可以做任何您想做的事情
    WriteLine($“步骤{u commandStep.StepName}:预执行”);
    _commandStep.Execute(cParams);
    WriteLine($“步骤{{u commandStep.StepName}:POST-EXECUTE”);
    }
    }
    /// 
    ///这是一个简单的工厂。您在这里封装了ICommandStep的创建,因此它将始终被装饰
    /// 
    公共类简单工厂
    {
    公共ICommandStep createStep()
    {
    返回新的ConcreteStepDecorator(新的ConcreteStep1());
    }
    }
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    var step=new SimpleStepFactory().createStep();
    步骤。执行(“参数”);
    Console.ReadLine();
    }
    }
    }
    
    此解决方案有两个优点:

    • 您可以使用许多decorator来包装步骤,也就是说,您可以在decorator中包装显示其名称的步骤,并在另一个显示参数的decorator中包装这两个步骤
    • 您不必修改您的步骤,因为所有额外的工作都是由装饰人员处理的

    这似乎效果不错。我喜欢这个结构。唯一的缺点是它需要在所有实现类中进行一些更改。您有这些解决方案的一些示例吗?我在原始注释中添加了带有Decorator模式的代码示例。模板方法模式已由背面显示。您不应该这样做,因为您正在强制执行实现细节。当然,您可以将这些方法添加到接口中,但同样,您是在对内部实现施加压力。为什么您觉得有必要规定如何在接口下实现某些东西?