2011-08-08 32 views
9

Una aplicación en la que estoy trabajando Procesos de trabajo. Dependiendo del estado de un elemento de trabajo, hay una cantidad de acciones disponibles. "Completo" "Cancelar" "Reasignar", etc ...Recomiende un patrón de diseño

para proporcionar la funcionalidad de las acciones actualmente tengo una interfaz que se ve algo como esto ...

public interface IActionProvider{ 
    public void Complete(WorkItem workItem); 
    public void Cancel (WorkItem workItem); 
    public void Reassign(WorkItem workItem); 
} 

A continuación, sobre la base de otros detalles de el elemento de trabajo Tengo implementaciones concretas de la interfaz. Sólo por ejemplo ...

public class NormalActionProvider :IActionProvider 
{ 
    ... 
} 

y

public class UrgentActionProvider : IActionProvider 
{ 
    .... 
} 

El problema es, si quiero añadir una nueva acción, digamos ... "Delegado" Tengo que actualizar la interfaz que por supuesto tiene efectos en todas las implementaciones.

¿Esto viola el principio de apertura/cierre? ¿Me pueden recomendar un patrón de diseño o refactor que pueda ayudarme aquí?

Respuesta

11

Parece que el patrón de comando sería adecuado. Puede modificar/agregar más comandos. Las clases de comando están desacopladas del programa principal.

public interface IActionProvider{ 
    public void execute(WorkItem item,ActionType actionType); 
} 

ActionType representa completa, Cancelar & así sucesivamente. Puede seguir añadiendo más clases de comando de los tipos de acción &.

0

Depende de lo que realmente esté tratando de lograr con su IActionProvider. Si realmente desea que cada implementación sea capaz de realizar todas las acciones que considere importantes, entonces debe formar parte de la interfaz que implementan. Las interfaces funcionan mejor si están bien planificadas con anticipación para que no tengan que cambiar continuamente.

Pero parece que no necesariamente quiere que todas las acciones sean implementadas por todos los proveedores. Necesitaría saber más detalles para poder dar un buen consejo, pero un ejemplo sería hacer que los proveedores se inicien contra un tipo de evento. Podrían suscribirse a los eventos que les interesan y realizar acciones solo para los eventos que tengan sentido para la implementación específica.

0

"Dependiendo del estado del elemento de trabajo", aporta el patrón de diseño Estado

un modo u otro, tendrá que refactorizar que proporcionan la interfaz y, finalmente, romper contratos de clientes.

Si he entendido bien su problema, tiene un WorkItemProcessor cuyo estado cambia según en el elemento de trabajo enviado a él.

lo tanto, su WorkItemProcessor convierte

// Context 
    public class WorkItemProcessor 
    { 
     public IState CurrentState { get; set; } 

     public WorkItemProcessor(IState initialState) 
     { 
      CurrentState = initialState; 
     } 

     public void Process(WorkItem workItem) 
     { 
      CurrentState.Handle(this, workItem); 
     } 
    } 

A continuación, definir múltiples estados que la WorkItemProcessor podría ser potencialmente en

// State Contract 
    public interface IState 
    { 
     void Handle(WorkItemProcessor processor, WorkItem item); 
    } 

    // State One 
    public class CompleteState : IState 
    { 
     public void Handle(WorkItemProcessor processor, WorkItem item) 
     { 
      processor.CurrentState = item.CompletenessConditionHoldsTrue ? (IState) this : new CancelState(); 
     } 
    } 

    // State Two 
    public class CancelState : IState 
    { 
     public void Handle(WorkItemProcessor processor, WorkItem item) 
     { 
      processor.CurrentState = item.CancelConditionHoldsTrue ? (IState) this : new CompleteState(); 
     } 
    } 

Asumiendo que su WorkItem Parece que

// Request 
    public class WorkItem 
    { 
     public bool CompletenessConditionHoldsTrue { get; set; } 

     public bool CancelConditionHoldsTrue { get; set; } 
    } 

para poner todo juntos

static void Main() 
    { 
     // Setup context in a state 
     WorkItemProcessor processor = new WorkItemProcessor(new CancelState()); 

     var workItem1 = new WorkItem { CompletenessConditionHoldsTrue = true }; 
     var workItem2 = new WorkItem { CancelConditionHoldsTrue = true }; 

     // Issue requests, which toggles state 
     processor.Process(workItem1); 
     processor.Process(workItem2); 

     Console.Read(); 
    } 

Espero que esto te acerque más. Aclamaciones.

0

También elegiría el patrón de comando. Como una mejora, puede combinarlo con el método abstracto de fábrica, para que pueda tener una clase de fábrica para cada clase de comando, y todas esas fábricas implementan una interfaz de fábrica común.

Por ejemplo:

// C# 
public interface ICommand { void Execute(); } 

public interface ICommandFactory { ICommand Create(); } 

public class CommandFactoryManager 
{ 
    private IDictionary<string, ICommandFactory> factories; 

    public CommandFactoryManager() 
    { 
     factories = new Dictionary<string, ICommandFactory>(); 
    } 

    public void RegisterCommandFactory(string name, ICommandFactory factory) 
    { 
     factories[name] = factory; 
    } 

    // ... 
} 

De esta manera, se puede registrar nuevas fábricas de mando de forma dinámica. Por ejemplo, puede cargar un archivo DLL en tiempo de ejecución y buscar todas las clases que implementan la interfaz ICommandFactory mediante reflexión, y tiene un sistema de complemento simple.