Aiuto con Iniezione di Dipendenza

4

Sono ancora molto confuso sul perché e su quando usare Dependency Injection. Se qualcuno potesse spiegare magari usando l'esempio qui sotto che sarebbe bello, qualsiasi altra spiegazione sarebbe apprezzata.

Diciamo che sto creando un'app web che salverà le recensioni dei film scritte in C # con ASP.NET MVC 5. Se ho il seguente codice modello ,

namespace MovieReviewProject.Models
    {
     public class MovieReviews
      {
        [Key]
        public int ReviewID_int{ get; set; }

        /// <summary>
        /// Submitter email address
        /// </summary>
        public string EmailAddress_str{ get; set; }

        /// <summary>
        /// Movie name
        /// </summary>
        public string MoveName_str{ get; set; }

        /// <summary>
        /// The review
        /// </summary>
        public string Review_str { get; set; }

        /// <summary>
        /// The submission date from
        /// </summary>
        public DateTime SubmissionDate_dt { get; set; }

        /// <summary>
        /// The movie rating
        /// </summary>
        public int Rating_int { get; set; }
    }
}

come sarebbe una classe che fornisce al controller l'elenco di tutte le recensioni, aggiunge una media per un film e più assomiglia?

So che il DI viene principalmente utilizzato per consentire un più facile test delle unità, ma a parte questo, quali sono i vantaggi? Vale la pena passare attraverso vecchi progetti e assicurarsi che tutti i fornitori stiano utilizzando questo principio?

    
posta ShadoWalker3065 24.02.2014 - 09:07
fonte

2 risposte

6

Sebbene la risposta di Doc Browns sia un approccio perfettamente valido e risolverà il tuo problema, ti suggerisco caldamente di investigare usando un approccio che usa oggetti Command e Query piuttosto che usare il pattern del repository.

Il modello di repository soffre di problemi relativi alle modifiche poiché ogni volta che hai bisogno di una query diversa devi aggiungere un nuovo metodo all'interfaccia del repository, dove avere oggetti Command e Query come cittadini di prima classe nel tuo progetto significa che puoi semplicemente aggiungere una nuova classe quando hai bisogno di una nuova query e non devi modificare alcun codice esistente. Significa anche che quando si desidera applicare i problemi trasversali (come la registrazione) alle query / ai comandi, è possibile farlo in un unico punto e avvolgere il comando / le query nel wrapper di registrazione.

Potresti implementarlo seguendo queste linee:

Potresti avere una classe di query come:

public class GetAllMovieReviewsQuery : IQuery<IEnumerable<MovieReview>>
{
     public GetAllMoveReviewsQuery(int movieId)
     {
          MovieId = movieId;
     }

     public int MovieId{get;private set;}
}

Questo è semplice e raccoglie solo i parametri di cui ha bisogno attraverso il suo costruttore, e dichiara il tipo del valore di ritorno della query.

E poi un gestore per quella query che effettivamente interroga il db:

public class GetAllMovieReviesQueryHandler : IQueryHandler<GetAllMoveReviewsQuery, IEnumerable<MovieReview>>
{
      private DbContext movieDbContext;

      public GetAllMovieReviesQueryHandler(DbContext movieDbContext)
      { 
           this.movieDbContext = movieDbContext;
      }

      public IEnumerable<MovieReview> Execute(GetAllMoveReviewsQuery query)
      {
           return dbContext.MovieReviews.Where(x=>x.MovieId == query.MovieId).ToList();
      }
}

quindi nel controller si inietta un oggetto che sa come trovare il gestore per qualsiasi query / comando (fondamentalmente un dizionario del tipo di una query / comando per l'istanza del gestore per quel comando di query) e basta chiamare questo

  class MyReviewController
  {
       public MyReviewController(IQueryDispatcher dispatcher)
       {
       }

       public IEnumerable<MovieReview> GetReviewsFromMovie(int movieId)
       {
            var query = new GetAllMovieReviewsQuery(movieId);
            return dispatcher.Execute(query);
       }
  }

Questo ha anche il vantaggio che puoi avere diverse fonti per le singole query, semplicemente sostituendo il gestore che gestisce quella query con una che cerca la risposta in un servizio web o altro.

Per testare l'unità, è sufficiente sostituire IQueryDispatcher nel controller con un'istanza fittizia che restituisce i valori da verificare con una determinata query.

Questo è un luogo eccellente per iniziare a leggere e copre anche una fiera un po 'su DI, ma ci sono altri chi attualmente pensa che il pattern del repository abbia avuto il suo giorno ed è più difficile del suo valore

    
risposta data 24.02.2014 - 11:50
fonte
5

Per un tale requisito, puoi utilizzare una classe MovieReviewsRepository con un'interfaccia IMovieReviewsRepository :

 interface IMovieReviewsRepository
 {
      IEnumerable<MovieReview> GetAllReviews(int movieID);
 }

Nel tuo controller, puoi iniettare un oggetto IMovieReviewsRepository tramite il costruttore:

 class MyReviewController
 {
       public MyReviewController(IMovieReviewsRepository repository)
       {
       }
 }

Ora sei libero di implementare l'interfaccia con una classe MovieReviewsRepository che fornisce gli oggetti da un database, o da una classe MovieReviewsRepositoryMock che fornisce, ad esempio, alcuni dati di test hardcoded senza alcun accesso al database. Ciò renderà possibile il test dell'unità reale. Ma permetterà anche di scambiare la fonte dei tuoi "oggetti di revisione cinematografica" con qualcosa di completamente diverso come un servizio web o un file senza cambiare il controller, solo fornendo diverse implementazioni IMovieReviewsRepository

Naturalmente, questo approccio potrebbe essere generalizzato a molte classi di modelli rendendo il tuo repository una classe generica, come è mostrato qui .

    
risposta data 24.02.2014 - 10:11
fonte