[英]How to enforce method execution order in c#
長話短說,我有以下 class:
public class FlowBasePipeline<T>
{
private List<StepBaseBusiness<T>> stepList = new List<StepBaseBusiness<T>>();
public void Push(StepBaseBusiness<T> step)
{
stepList.Add(step);
}
public void Trigger(T result)
{
foreach (var step in stepList )
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
我正在尋找的是強制程序員首先調用Push
方法,然后讓他們訪問Trigger
方法,在這種情況下,不允許以下場景
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Trigger()// Trigger method is not recognized
我們應該先調用Push
方法
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep()).Trigger()//Now Trigger is recognized
我做了什么:
我應用了如下顯式接口方法實現以使其工作:
public interface IBasePipeline<T> where T:BaseResult,new()
{
void Trigger();
IBasePipeline<T> Push(StepBaseBusiness<T> step);
}
public class FlowBasePipeline<T>:IBasePipeline<T> where T:BaseResult,new()
{
private List<StepBaseBusiness<T>> stepList = new List<StepBaseBusiness<T>>();
public IBasePipeline<T> Push(StepBaseBusiness<T> step)
{
stepList.Add(step);
return this;
}
void IBasePipeline<T>.Trigger(T result)
{
foreach (var step in stepList )
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
現在它運行良好,我們無法在Push
方法之前訪問Trigger
方法,但從我的角度來看,這不是一個好方法,因為我們可能需要更多級別的訂單,我不知道如何以這種方式完成。
據我所知,方法鏈接是函數式編程的關鍵規則之一。
是否有任何模式或策略來實現這種鏈接?
更新:
我們需要多次調用 push 方法
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep1()).Push(new MyStep2()).Trigger();
第一次推送后,推送和觸發器將可用。
一種方法是使用接口通過指定接口作為結果來限制對特定方法的訪問。
public interface IStartCar
{
IDriveCar Start(string key);
}
public interface IDriveCar
{
IParkCar Drive(string address);
}
public interface IParkCar
{
IStopCar Park();
}
public interface IStopCar
{
IParkCar Drive(string address);
void Stop();
}
public class Car : IStartCar, IDriveCar, IParkCar, IStopCar
{
public IDriveCar Start(string key);
public IParkCar Drive(string address);
public IStopCar Park();
public IStopCar Park();
private Car() { }
public static IStartCar Get()
{
var result = new Car();
return result;
}
}
現在要獲取汽車,您使用 CarFactory 方法Get()
,它返回汽車,但您實際上只能訪問接口結果。 此模式僅允許開發人員將特定方法串在一起:
var car = Car.Get();
car.Start("key").Drive("address1").Park().Drive("address2").Park().Stop();
幾個小時后,我想出了這個設計:
public interface IBasePipelineRegister<T> where T:BaseResult
{
IStagePipeline<T> Push(StepBaseBusiness<T> step);
List<StepBaseBusiness<T>> Steps { get; set; }
}
public interface IBasePipelineTrigger<T> where T:BaseResult
{
void Trigger(T result);
}
public interface IStagePipeline<T>: IBasePipelineTrigger<T>,IBasePipelineRegister<T> where T:BaseResult
{
}
public class FlowBasePipeline<TResult> : IBasePipelineRegister<TResult> where TResult : BaseResult,new()
{
public List<StepBaseBusiness<TResult>> Steps { get ; set ; }
private IStagePipeline<TResult> _stagePipeline;
public BasePipeline()
{
this.Steps = new List<StepBaseBusiness<TResult>>();
this._stagePipeline = new StagePipeline<TResult>(this);
}
public IStagePipeline<TResult> Push(StepBaseBusiness<TResult> step)
{
Steps.Add(step);
return _stagePipeline;
}
}
如您所見, BasePipeline
僅實現了IBasePipelineRegister
和 Register 方法提供了新的 StagePipeline class,它由當前的 class 和觸發器實現組成。
public class StagePipeline<T>: IStagePipeline<T> where T:BaseResult
{
private readonly IBasePipelineRegister<T> pipelineRegister;
public List<StepBaseBusiness<T>> Steps { get; set; }
public StagePipeline(IBasePipelineRegister<T> pipelineRegister)
{
this.pipelineRegister = pipelineRegister;
Steps = pipelineRegister.Steps;
}
public IStagePipeline<T> Push(StepBaseBusiness<T> step)
{
return pipelineRegister.Push(step);
}
public void Trigger(T result)
{
foreach (var step in Steps)
{
result = step.Execute(result);
if (!result.IsSuccess)
{
break;
}
}
}
}
現在,每種方法都添加了一項新功能,而不是替換新功能。
var pipeline=new FlowBasePipeline<MyStepResult>();
pipeline.Push(new MyStep1()).Push(new MyStep2()).Trigger();
我用於 api 的方法示例,它固有地用流暢的語法“引導”調用者:
public class Pipeline
{
readonly List<Action> _steps = new List<Action>();
// only Push is available when Pipeline is initialized
public PipelineWithSteps Push(Action step)
{
_steps.Add(step);
// or cache this if you want 'Push' repeatable
return new PipelineWithSteps(this);
}
public class PipelineWithSteps
{
// not required but often the chained context wants/needs access to the first context
readonly Pipeline _context;
// api is public but ctor cannot be invoked by external caller
internal PipelineWithSteps(Pipeline context) => _context = context;
// now Trigger is available only after something was pushed
public PipelineWithSteps Trigger()
{
foreach(var step in _context._steps)
step();
Console.WriteLine();
return this;
}
// usually I don't repeat an initialization method;
// this could be done using the 'context'
// but would have to be refactored to return the existing 'PipelineWithSteps'
public PipelineWithSteps Push(Action step)
{
_context._steps.Add(step);
return this;
}
}
}
用法:
var pipeline = new Pipeline();
pipeline.Push(() => Console.WriteLine("A"))
.Push(() => Console.WriteLine("B"))
.Trigger()
.Push(() => Console.WriteLine("C"))
.Trigger();
Output:
A
B
A
B
C
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.