2012-06-21 5 views
5

Tengo una serie de tareas que básicamente es una variación del patrón de la cadena de responsabilidad.Ejecución de la cadena de variación de responsabilidad

Una tarea en mi tubería se ve de la siguiente manera

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

..y mi procesador parece

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

y mi aplicación concreta tiene el siguiente aspecto:

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

.. y mis tareas se ven así:

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

T pueden ser instancias diferentes, pero vinculadas por un contrato genérico. Una de las tareas consiste en mapear el objeto entrante en un objeto completamente diferente y reenviar esa instancia desde allí en adelante.

Ahora, como es de ver, soy la ejecución de todas las tareas en la tubería, me gustaría modificar esto para lo siguiente:

  • de entrada para el método Execute para la siguiente tarea debe ser de la tarea ejecutada previamente.
  • Si el CanExecute falla para una tarea, la tubería debe detener el procesamiento de las tareas.

Puede ayudarme a conseguir esto. ¿También esperaría que el código se estructurara de manera diferente para este propósito?

Respuesta

3

¿Qué tal esto:

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

     result = individual.Process(result); 
    } 

    return result; 
} 

Como lo tienes actualmente, es mucho más parecido a un patrón compuesto de una cadena de responsabilidad. Este cambio lo hace un poco más CoR-ish. Pero es más importante observar si satisface sus necesidades que utilizar la jerga de patrón de diseño correcto. :)

3

Con esta implementación, el CanProcess se usa realmente para activar una excepción que detendrá el proceso.

Agregué una segunda implementación, llamada ExecuteWithPartial, que maneja la excepción, en caso de que ese sea el comportamiento que está esperando. Procesa, pero si hay un error, devuelve el resultado parcial hasta ese punto.

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

y la nueva clase de excepción es:

public class CantExecuteException : Exception 
{ 
} 
Cuestiones relacionadas