执行责任链变更

时间:2012-06-21 17:35:38

标签: c# linq c#-4.0 chain-of-responsibility

我有一系列任务,基本上是责任链模式的变体。

我的管道中的任务如下所示

internal interface IPTask<T>
{
    bool CanExecute(T instance);
    T Process(T instance);
}

..我的处理器看起来像

internal interface IProcessor<T>
{
    T Execute(T instance);
}

我的具体实现如下:

public class Processor<T> : IProcessor<T>
{
    private readonly ITasks<T> tasks;

    public Processor(ITasks<T> tasks)
    {
        this.tasks= tasks;
    }

    public T Execute(T instance)
    {
         var taskstoExecute = tasks.GetTasks()
                                   .Where(task => task.CanExecute(instance));

         taskstoExecute.ToList().ForEach(task=>task.Process(instance));

         return T;
    }
}

..我的任务看起来像这样:

internal interface ITasks<T>
{
    IEnumerable<IPTask<T>> GetTasks();
}

T可以是不同的实例,但受通用合同的约束。其中一项任务是将传入对象映射到完全不同的对象,并从那里开始转发该实例。

正如您所看到的,我正在执行管道中的所有任务,我想将其修改为以下内容:

  • 下一个任务的Execute方法的输入应来自先前执行的任务。
  • 如果CanExecute未能完成任务,则管道应停止处理任务。

你能帮我解决这个问题。您是否还希望为此目的以不同的方式构建代码?

2 个答案:

答案 0 :(得分:3)

通过此实现,CanProcess实际上用于触发将停止进程的异常。

我添加了一个名为ExecuteWithPartial的第二个实现,它处理异常,以防这是您期望的行为。它会处理,但是如果有错误,它会将部分结果返回到该点。

public class Processor<T> : IProcessor<T>
{
    //... rest of your code

    public T Execute(T instance)
    {
        return this._tasks.GetTasks().Aggregate(instance, (current, task) => InternalExecute(task, current));
    }

    public T ExecuteWithPartial(T instance)
    {
        var target = instance;
        try
        {
            foreach (var task in this._tasks.GetTasks())
            {
                target = InternalExecute(task, target);
            }
            return target;
        }
        catch (CantExecuteException)
        {
            return target;
        }
    }


    private static T InternalExecute(IPTask<T> task, T instance)
    {
        if (!task.CanExecute(instance))
            throw new CantExecuteException();
        return task.Process(instance);
    }
}

新的Exception类是:

public class CantExecuteException : Exception
{
}

答案 1 :(得分:3)

这个怎么样:

public T Execute(T instance)
{
     T result = instance;
     foreach(var individual in tasks.GetTasks())
     {
         if(!individual.CanExecute()) break;

         result = individual.Process(result);
     }

     return result;
}

正如你现在所拥有的那样,它更像是一个复合模式,而不是一个责任链。这种变化使它更具有CoR-ish。但更重要的是要注意它是否满足您的需求,而不是使用正确的设计模式术语。 :)