Путаница сервисного локатора - PullRequest
3 голосов
/ 30 марта 2011

Я просто пишу класс, реализующий шаблон ServiceLocator.

   public class ServiceFactory : IServiceFactory
    {
        private IDictionary<Type, object> instantiatedServices;

        public ServiceFactory()
        {
            instantiatedServices = new Dictionary<Type, object>();
        }

        public T GetService<T>() where T : class, new()
        {
            if (this.instantiatedServices.ContainsKey(typeof(T)))
            {
                return (T)this.instantiatedServices[typeof(T)];
            }
            else
            {
                T service = new T();

                instantiatedServices.Add(typeof(T), service);

                return service;
            }
        }
    }

Теперь у меня есть несколько вопросов:

1.) Откуда мне вызвать этот класс?app.xaml.cs делает вещи wpf?

2.) Должен ли я регистрировать службы, если да, где мне это делать?

3.) Когда я выполняю ленивую инициализацию службы "ICustomerService ", почему тогда я должен создать метод Register (T service) для него?это двойная работа.

4.) Стоит ли мне вообще искать сервисный локатор?

ОБНОВЛЕНИЕ

В данный момент я чувствую, что долженИзнасиловать DI-инструмент для моих индивидуальных целей, которые являются =>

App.xaml.cs => Здесь я создаю MainWindow и устанавливаю его текст данных в MainViewModel.cs

public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            var mainVM = new MainViewModel();
            var mainWindow = new MainWindow();
            mainWindow.DataContext = mainVM;
            mainWindow.ShowDialog();            
        }        
    }

MainViewModel.cs => Здесь я предварительно загружаю / настраиваю данные, которые мне нужны для определенных Controller / ViewModel, таких как LessonPlannerDailyViewModel или LessonPlannerWeeklyViewModel и т. Д. *

public class MainViewModel : SuperViewModel
{     

        private LightCommand _newSchoolYearWizardCommand;       
        private LightCommand _showSchoolclassAdministrationCommand;
        private LightCommand _showLessonPlannerDailyCommand;
        private LightCommand _showLessonPlannerWeeklyCommand;  
        private LightCommand _openSchoolYearWizardCommand;

        private SuperViewModel _vm;
        private FadeTransition _fe = new FadeTransition();

        private readonly IMainRepository _mainService;
        private readonly ILessonPlannerService _lessonPlannerService;
        private readonly IAdminService _adminService;
        private readonly IDocumentService _documentService;     
        private readonly IMediator _mediator;

        private readonly  IDailyPlanner _dailyVM;
        private readonly  IWeeklyPlanner _weeklyVM;
        private SchoolclassAdministrationViewModel _saVM;    


        public MainViewModel()  
        {

            // These are a couple of services I create here because I need them in MainViewModel

            _mediator = new  Mediator();            
            _mainService = new MainRepository();
            _lessonPlannerService = new LessonPlannerService();
            _adminService = new AdminService();
            _documentService = new DocumentService();    

            this._mediator.Register(this);  

            InitSchoolclassAdministration();                     
        } 

        //... Create other ViewModel/Controller via button commands and their execute method
}  

Вкл.другой видовой моделью является LessonPlannerDailyViewModel.cs => Здесь я создаю привязываемую коллекцию объектов PeriodViewModel, которые принимают в своем конструкторе некоторые службы.В следующем абзаце после следующего кода см. DocumentListViewModel.cs, созданный ONE PeriodViewModel, который снова принимает службы - то же, что я создал в MainViewModel ... -

 public class LessonPlannerDailyViewModel : LessonPlannerBaseViewModel, IDailyPlanner
    {    
        private ILessonPlannerService _lpRepo;
        private IMainRepository _mainRepo;
        private IMediator _mediator;
        private IDocumentService _docRepo;

        private ObservableCollection<PeriodViewModel> _periodListViewModel;      

        private LightCommand _firstDateCommand;
        private LightCommand _lastDateCommand;
        private LightCommand _nextDateCommand;
        private LightCommand _previousDateCommand;  

        public LessonPlannerDailyViewModel(IMediator mediator, ILessonPlannerService lpRepo, IMainRepository mainRepo, IDocumentService docRepo)
        {
            _mediator = mediator;
            _lpRepo = lpRepo;
            _mainRepo = mainRepo;
            _docRepo = docRepo;

            _mediator.Register(this);

            SchoolYear schoolyear = _mainRepo.GetSchoolYear();

            MinDate = schoolyear.Start;
            MaxDate = schoolyear.End;         

            SelectedDate = DateTime.Now; 
        } 

        private void LoadLessonPlannerByDay(DateTime data)
        {
            _periodListViewModel = new ObservableCollection<PeriodViewModel>();

            _lpRepo.GetLessonPlannerByDay(data).ForEach(p =>
            {
                _periodListViewModel.Add(new PeriodViewModel(p, _lpRepo, _docRepo));
            });          

            PeriodListViewModel = _periodListViewModel;        
        } 

        private DateTime _selectedDate;
        public DateTime SelectedDate
        {
            get { return _selectedDate; }
            set
            {
                if (_selectedDate.Date == value.Date)
                    return;

                _selectedDate = value;
                this.RaisePropertyChanged("SelectedDate");

                LoadLessonPlannerByDay( value );
            }
        }

       // ...

}

PeriodViewModel.cs => Каждая DataRow в моей DataGrid имеет Период, а Период имеет определенную ячейку данных, преобразованную в DocumentListViewModel - Период 1 имеет N Документов, это отношение FYI ... поэтому PeriodViewModel создает DocumentListViewModel.

public class PeriodViewModel : SuperViewModel
    {  
        private Period _period;
        private ILessonPlannerService _lpRepo;

        public PeriodViewModel(Period period, ILessonPlannerService lpRepo, IDocumentService docRepo)
        {            
            _period = period;
            _lpRepo = lpRepo;

            // Update properties to database
            this.PropertyChanged += (o, e) =>
            {
                switch (e.PropertyName)
                {
                    case "Homework": _lpRepo.UpdateHomeWork(PeriodNumber, LessonDayDate, Homework); break;
                    case "Content": _lpRepo.UpdateContent(PeriodNumber, LessonDayDate, Content); break;
                }
            };

            Documents = new DocumentListViewModel(_period.Id, period.Documents, docRepo); 
        }
   //...
}

DocumentListViewModel.cs => Здесь я настраиваю команды для добавления / удаления / открытия документа, и это можно сделать с помощью documentService / documentRepository

public class DocumentListViewModel : SuperViewModel
    {
        private LightCommand _deleteDocumentCommand;
        private LightCommand _addDocumentCommand;
        private LightCommand _openDocumentCommand;      

        private int _parentId;

        private readonly IDocumentService _documentService;       

        public DocumentListViewModel(int parentId,ObservableCollection<Document> documents, IDocumentService documentService)
        {
            _parentId = parentId;
            _documentService = documentService;
            DocumentList = documents;
            SelectedDocuments = new ObservableCollection<Document>();
        } 

        // ...
} 

Чтобы подвести итог проблемы:Видите ли вы цепочку объектов, каскадирующих сервисы сверху:

MainViewodel -> LessonPlannerDailyViewModel -> PeriodViewModel -> DocumentListViewModel

Мне нужно каскадировать их, потому что если я не использую статический локатор службЯ могу убедиться, что один экземпляр службы только когда якаскадирование сервисов ...

Как инструмент DI может помочь мне КОНКРЕТНО в создании приложения wpf по шаблону MVVM?

Ответы [ 2 ]

5 голосов
/ 30 марта 2011

На четвертый вопрос проще всего ответить: нет, вы вообще не должны обращаться за сервисным локатором, потому что это анти-паттерн .

Так в чем же альтернатива? Используйте шаблон Register Resolve Release . Это должно стать хорошей отправной точкой для ответа на другие ваши вопросы.

1 голос
/ 30 марта 2011
  1. Вы бы назвали это всякий раз, когда вам нужен экземпляр услуги T. Вам потребуется более надежный код для обработки случаев, когда у вас нет никакой логики для обработки, когда T неизвестен или не может быть обработан вашим локатором службы.

  2. Это варьируется от приложения к приложению, но чаще всего регистрация служб происходит в точке входа приложения, например, в приложениях Windows перед загрузкой формы, в приложениях ASP.NET, в методе Application_Start, в службах, когда загружается метод service Main. Это вызов для конкретного приложения, который вы должны сделать в зависимости от ваших потребностей. Обратите внимание, что обычно это разовый звонок.

  3. Если вы хотите выставить ленивую инициализацию, тогда у вас должно быть два метода регистрации, один из которых будет использовать экземпляр T (если вы хотите всегда использовать этот один экземпляр), или другой, который принимает Func<T>, которая может быть вызвана, когда требуется экземпляр (и затем, если необходимо, кэширована).

  4. Если под этим вы подразумеваете, что напишите один самостоятельно, то я должен был бы решительно сказать нет, это уже сделано для вас , и если вам не нравится этот уровень детализации, есть ничто не мешает вам использовать такие инструменты, как Ninject , Unity или любой другой инструмент DI.

...