2013-06-18 15 views
5

Io uso il Castello di Windsor già da un po 'di tempo. È perfetto per gli ambienti in cui i dati si trovano in un database o simili, dove il modello di repository o il modello unitofwork funzionano bene.Castello di Windsor/DI e modelli di oggetti

Ora ho una situazione diversa: ho un modello di oggetto complesso che è assemblato da molti PONO singoli. L'ambiente è fortemente influenzato dalla COM, per renderlo più esplicito: Excel, i PIO di Word sono molto utilizzati.

Io uso lo schema di comando, ho implementato ICommandHandler come descritto here ma con una differenza. Poiché desidero assemblare i comandi a un elenco di comandi per chiamarli in una corsa senza conoscere nulla, oltre allo schema di comando generale descritto, non introduce il contesto quando chiama il metodo execute. Quindi l'interfaccia è simile a questa:

public interface ICommand 
    { 
     void Execute(); 
     bool CanExecute(); 
    } 

L'esecuzione di comandi con tale interfaccia è efficace e di facile comprensione. D'altra parte è un problema introdurre il contesto con il ctor perché, pertanto, il contenitore deve essere chiamato esplicitamente ad es. aggiungi i parametri del ctor.

Così io in realtà sono due domande:

  1. E 'possibile iniettare un - chiamiamolo un contesto, una parte del modello di oggetti - automaticamente dal castello di Windsor senza chiamare il contenitore explictely?
  2. Come partecipare dal modello di comando utilizzando DI? Qualche idea su come realizzare la capacità di definire un elenco di attività/azioni o simili seguendo la regola RRR descritta here?
+0

Si collega a una descrizione del modello di comando/gestore (utilizzando 'ICommandHandler '), ma in realtà si utilizza il modello di comando, che è completamente diverso, poiché i comandi nel modello di comando/gestore sono DTO senza comportamento, e non contengono il metodo 'Esegui'. Avere un metodo 'Execute' su di essi disabilita la maggior parte delle funzionalità che il pattern command/handler porta. I problemi relativi all'iniezione delle dipendenze nei comandi spariranno quando si iniettano le dipendenze nei gestori. Nel modello command/handler, i comandi non hanno alcuna dipendenza (perché non hanno alcun comportamento). – Steven

+0

Grazie per la risposta, Steven. Hai certamente ragione, posso iniettarli nel conduttore. Ma questo non risolve il problema, perché devo ancora iniettare le stesse informazioni e chiamare il contenitore per rendere i miei dati disponibili al gestore. Non sarebbe possibile eseguire comandi batch ed eseguirli in fila. Ho sbagliato qualcosa? –

risposta

4

Infrastrutture:

public interface ICommandHandler<in T> 
{ 
    void Handle(T command); 
} 

public interface ICommandExecutor 
{ 
    CommandResult ExecuteCommand(Command command); 
    CommandResult ExecuteCommands(Command[] commands); 
} 

public abstract class Command 
{ 

} 

public class CommandExecutor : ICommandExecutor 
{ 
    private readonly IWindsorContainer _kernel; 

    public CommandExecutor(IWindsorContainer kernel) 
    { 
     Guard.AssertNotNull(() => kernel); 
     _kernel = kernel; 
    } 

    public CommandResult ExecuteCommand(Command command) 
    { 
     return ExecuteInternal(command); 
    } 

    public CommandResult ExecuteCommands(Command[] commands) 
    { 
     CommandResult result = null; 

     foreach (Command command in commands) 
     { 
      result = ExecuteInternal(command); 

      if (!result.IsExecuted) 
       return result; 
     } 

     return result ?? CommandResult.Executed("Command executed successfully"); 
    } 

    private CommandResult ExecuteInternal(Command command) 
    { 
     dynamic handler = FindHandlerForCommand(command); 

     try 
     { 
      handler.Handle(command as dynamic); 
      return CommandResult.Executed("Command executed successfully"); 
     } 
     finally 
     { 
      _kernel.Release(handler); 
     } 
    } 

    private object FindHandlerForCommand(Command command) 
    { 
     Type handlerType = typeof (ICommandHandler<>).MakeGenericType(command.GetType()); 
     dynamic handler = _kernel.Resolve(handlerType); 
     return handler; 
    } 
} 

Registrazione:

 container.Register(Component.For<ICommandExecutor>().ImplementedBy<CommandExecutor>() 
      .Interceptors<ExceptionToCommandResult>() 
      .Interceptors<ExceptionLogger>() 
      .Interceptors<HandleWhenDeadlockVictim>() 
      .Interceptors<RetryCommand>() 
      .Interceptors<ContainerScopeWrapper>() 
      .Interceptors<TransactionWrapper>() 
      .Interceptors<SameNhibernateSessionAndTransactionWrapper>()); 

Esempio:

public class WriteComment : Command 
{ 
    public string GameToCommentId { get; set; } 

    public string Comment { get; set; } 
} 

public class WriteCommentCommandHandler : ICommandHandler<WriteComment> 
{ 
    private readonly IGameRepository _repository; 

    public WriteCommentCommandHandler(IGameRepository repository) 
    { 
     Guard.AssertNotNull(() => repository); 
     _repository = repository; 
    } 

    public void Handle(WriteComment command) 
    { 
     var game = _repository.Get(new Guid(command.GameToCommentId)); 

     game.WriteComment(command.Comment, DateTime.Now); 
    } 
} 

Tutta quella roba AOP gestisce le transazioni e così via. Il comando executor è un singleton stateless, i gestori specificano le loro diverse esigenze. Il comando executor è solo infrastruttura e indipendente dal dominio, quindi posizionalo dove preferisci al di fuori del tuo dominio. Questo è il codice di produzione su un grande sistema, funziona come un fascino.

+0

Marius, molte grazie. Abbastanza completo. Ci proveremo! –

Problemi correlati