2012-06-21 18 views
5

Ho una serie di attività che fondamentalmente è una variante del modello di catena di responsabilità.Esecuzione della variazione della catena di responsabilità

Un compito nel mio cantiere sembra come di seguito

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

..e il mio processore sembra

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

e la mia concreta applicazione si presenta così:

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

.. e i miei compiti assomigliano a questo:

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

T potrebbe essere istanze diverse, ma vincolato da un contratto generico. Uno dei compiti riguarda la mappatura dell'oggetto in entrata in un oggetto completamente diverso e l'inoltro dell'istanza da lì in poi.

Ora, come si vedrebbe, che sto eseguendo tutti i compiti in cantiere, vorrei modificare questo al seguente:

  • Input per il metodo Execute per il prossimo compito dovrebbe essere dalla compito precedentemente eseguito.
  • Se lo CanExecute non riesce per un'attività, la pipeline dovrebbe interrompere l'elaborazione delle attività.

Potete per favore aiutarmi a ottenere questo. Inoltre, ti aspetteresti che il codice sia strutturato diversamente per questo scopo?

risposta

3

ne dite di questo:

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

     result = individual.Process(result); 
    } 

    return result; 
} 

Come lo avete attualmente, è molto più simile a un composite di una catena di responsabilità. Questo cambiamento rende un po 'più CoR-ish. Ma è più importante notare se soddisfa i tuoi bisogni piuttosto che usare il gergo del modello di progettazione corretto. :)

3

Con questa implementazione, lo CanProcess viene effettivamente utilizzato per attivare un'eccezione che interromperà il processo.

Ho aggiunto una seconda implementazione, denominata ExecuteWithPartial, che gestisce l'eccezione, nel caso in cui questo è il comportamento che ci si aspetta. Elabora ma se c'è un errore, restituisce il risultato parziale fino a quel 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); 
    } 
} 

e la nuova classe Exception è:

public class CantExecuteException : Exception 
{ 
} 
Problemi correlati