服务定位器混乱

时间:2011-03-29 20:47:50

标签: c# dependency-injection service-locator

我只是在编写一个实现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服务)方法呢?这就是双重工作。

4.。)我应该去寻找服务定位器吗?

更新

目前我觉得我必须为个人目的强奸DI工具=&gt;

App.xaml.cs =&gt;在这里,我创建MainWindow并将其datacontext设置为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 =&gt;在这里,我预装/设置我需要的某些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
}  

另一个ViewModel是 LessonPlannerDailyViewModel.cs =&gt;在这里,我创建了一个可绑定的PeriodViewModel对象集合,它们为构造函数提供了一些服务。在下面的代码之后的下一段看到由一个PeriodViewModel创建的DocumentListViewModel.cs,它再次获取服务 - 与我在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 =&gt;我的DataGrid中的每个DataRow都有一个Period和一个Period有一个特定的单元格,该文件被指定为DocumentListViewModel - Period 1有N个Document是关系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 =&gt;在这里,我设置了添加/删除/打开文档的命令,这可以通过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 - &gt; LessonPlannerDailyViewModel - &gt; PeriodViewModel - &gt; DocumentListViewModel

我需要级联它们,因为如果我不使用静态服务定位器,我只能确保在级联服务时有一个服务实例...

这里的DI工具如何帮助我 CONCRETELY 按照MVVM模式执行wpf应用程序?

2 个答案:

答案 0 :(得分:5)

第四个问题是最容易回答的问题:不,您根本不应该使用服务定位器,因为it's an anti-pattern

那么替代方案是什么?使用Register Resolve Release pattern。这应该是回答你的其他问题的一个很好的起点。

答案 1 :(得分:1)

  1. 只要您需要服务实例T,就可以调用此方法。您需要更强大的代码来处理您没有任何逻辑来处理T未知或服务定位器无法处理的情况。

  2. 这因应用程序而异,但最典型的是,服务注册发生在应用程序入口点,例如:在Windows应用程序中,在加载表单之前,在ASP.NET应用程序中,在Application_Start方法中,在服务中,加载服务Main方法时。这是一个特定于应用程序的调用,您必须根据需要进行调用。请注意,它通常是一次性调用。

  3. 如果你想公开延迟初始化,那么你应该有两个注册方法,一个将采用T的实例(如果你想总是使用那个实例),或者一个一个Func<T>,可以在需要实例时调用(如果需要,可以缓存)。

  4. 如果这意味着你自己写一个,那么我必须强调说不,它是already been done for you,如果你不喜欢这种级别的粒度,没有什么能阻止你使用工具比如NinjectUnity或任何其他DI工具。