Service Locator confusion
I am just writing a class implementing the ServiceLocator pattern.
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;
}
}
}
Now I have several questions:
1.) Where should I call this class from? the app.xaml.cs doing wpf stuff?
2.) Should I register services , if yes where should I do that?
3.) When I do lazy Initialization of the service "ICu开发者_如何学JAVAstomerService" why then should I create a Register(T service)-method for it? thats double work.
4.) Should I go at all for a service locator?
UPDATE
At the moment I feel I have to rape a DI tool for my individual purposes which are =>
App.xaml.cs => Here I create the MainWindow and set its datacontext to the 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 => Here I preload/setup data which I need for certain Controller/ViewModel`s like the LessonPlannerDailyViewModel or LessonPlannerWeeklyViewModel etc...
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
}
On of the other ViewModel is the LessonPlannerDailyViewModel.cs => Here I create a bindable collection of PeriodViewModel objects which take in their constructor some services. At next paragraph after the following code see the DocumentListViewModel.cs created by ONE PeriodViewModel which takes again services - the same that I created in the 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 => Every DataRow in my DataGrid has a Period and a Period has a certain cell datatemplated to the DocumentListViewModel - Period 1 has N Documents is the relation FYI... so a PeriodViewModel creates a 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 => Here I setup the commands for add/delete/open a document and this can be done with the 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>();
}
// ...
}
To sum the problem up: Do you see the chain of objects cascading the services from top:
MainViewodel -> LessonPlannerDailyViewModel -> PeriodViewModel -> DocumentListViewModel
I need to cascade them because if I am not using a static service locator I can only make sure to have ONE instance of a service when I am cascading the services...
How can a DI tool here help me CONCRETELY doing a wpf app following the MVVM pattern?
The fourth question is the easiest to answer: no, you shouldn't go for Service Locator at all because it's an anti-pattern.
So what is the alternative? Use the Register Resolve Release pattern. That should be a good starting point to answer your other questions.
You would call this whenever you need an instance of a service
T
. You would need more robust code to handle the cases where you don't have any logic to handle whereT
is unknown or unable to be handled by your service locator.This varies from application to application, but most typically, registration of services happens at the application entry point, e.g. in Windows applications, before the form is loaded, in ASP.NET applications, in the
Application_Start
method, in services, when the serviceMain
method is loaded. This is an application-specific call that you have to make depending on your needs. Note it is typically a one-time call.If you want to expose lazy initialization, then you should have two registration methods, one which will take an instance of
T
(if you want to always use that one instance), or one that takes aFunc<T>
, which can be called when the instance is needed (and then cached, if desired).If by this you mean write one yourself, then I would have to emphatically say no, it's already been done for you and if you don't like that level of granularity, there is nothing stopping you from using tools like Ninject, Unity or any of the other DI tools out there.
精彩评论