我应该将 View Model 传递给我的服务吗?如果是,该怎么做?
Should I pass View Model to my service, and if yes, how to do it?
我有一个解决方案,它使用 Autofac,并且我将一些方法从我的视图模型移到了服务文件中。现在我面临一个问题,服务方法中的一些变量引用了 VM 属性。所以我想通了,也许我应该将视图模型传递给服务。
首先,为了层分离和可测试性,我不确定我是否应该这样做。不过我猜的,mocking应该是没问题的,不对请指正
另一件事是我还不确定如何将虚拟机传递给服务。使用我当前的解决方案,您可以在下面找到,我在 Model 道具的 setter 上遇到 Whosebug
异常。问题是,现在这是我拥有的最好的,我没有任何新想法。
另一件事,如果将 VM 传递到服务层是一种反模式,我应该如何从服务层引用 VM 属性?我是否应该为此创建一些包装器,VM 和服务将引用它?
代码将在简化示例中显示。 MainViewModel:
public class MainViewModel : ViewModelBase
{
private MainViewModel _vm;
private Person _person;
private ISomeService _someService;
public MainViewModel(ISomeService someService)
{
_person = new Person();
_someService = someService;
Name = "Slim Shady";
_vm = new MainViewModel(_someService);
Execute();
}
public string Name
{
get
{
return _person.Name;
}
set
{
_person.Name = value;
OnPropertyChanged();
}
}
private void Execute()
{
string dupa = _someService.GetTheName(_vm);
System.Windows.MessageBox.Show(dupa);
}
}
型号:
public class Person
{
public string Name { get; set; }
}
服务:
public interface ISomeService
{
string GetTheName(ViewModel.MainViewModel _vm);
}
public class SomeService : ISomeService
{
public string GetTheName(MainViewModel _vm)
{
return _vm.Name;
}
}
Autofac:
public class BootStrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<SomeService>()
.As<ISomeService>().SingleInstance();
builder.RegisterType<MainWindow>().AsSelf();
builder.RegisterType<MainViewModel>().AsSelf().SingleInstance();
return builder.Build();
}
}
更新
还需要考虑一些其他服务也会引用 Person.
的 Name 属性 的情况
我认为这里存在责任倒置。
如果您的服务必须产生数据,它必须保存这些数据。这不是 VM 的工作。
因此,在您的示例中,Name 是 Person 的 属性,并且反过来成为您 VM 中 getter 方法的结果。
我不知道 Autofac,但我认为您的服务应该持有 Person 对象,并将其提供给 VM(通过 IoC)。
不过,我们仍然缺少上下文信息以获取完整且合适的答案。
如果 Person 需要在 VM 中实例化,您可以简单地在 VM 中告诉您的服务实例化它,然后 return 它:
public MainViewModel(ISomeService someService)
{
_someService = someService;
_person = _someService.GetPerson("John");
//etc
}
public interface ISomeService
{
Person GetPerson(string name);
}
public class SomeService : ISomeService
{
private List<Person> personRepository;
//insert constructor...
public Person GetPerson(string name)
{
return personRepository.Single(person => person.Name == name);
}
}
简而言之,服务不应该知道 VM,甚至不应该知道 VM 是什么。
Should I pass View Model to my service, and if yes, how to do it?
不,你不应该。服务不应该对视图模型有任何依赖性。正好相反。
Another thing, if passing a VM to the Service layer is an antipattern, how should I refer a VM property from the Service layer?
你不知道。该服务应该 return 视图模型可能需要的任何数据,但它不应该知道任何关于视图模型类型本身的信息。
在您的示例中,服务应该只是 return 一个字符串:
public string GetTheName()
{
return "...";
}
如果这个字符串来自视图模型,那么首先使用服务来检索它是没有意义的。然后您可以直接在视图模型 class 中访问 this.Name
。
如果服务以某种方式操纵名称 string
,它应该接受 string
作为参数和 return 另一个字符串,例如:
public string GetTheName(string name)
{
return name.Trim();
}
最终解决方案
在我创建的服务层中:
public interface IPersonService
{
string Name { get; set; }
}
public class PersonService : IPersonService
{
Person _personModel = new Person();
public string Name
{
get
{
return _personModel.Name;
}
set
{
_personModel.Name = value;
}
}
}
并修改:
public interface ISomeService
{
string GetTheName(IPersonService personService);
}
public class SomeService : ISomeService
{
public string GetTheName(IPersonService personService)
{
return personService.Name;
}
}
所以现在我将两种服务都注入到我的 VM 中,当从 SomeService
中检索名称时,我正在通过注入 PersonServie
:
public class MainViewModel : ViewModelBase
{
private IPersonService _personService;
private ISomeService _someService;
public MainViewModel(ISomeService someService, IPersonService personService)
{
_personService = personService;
_someService = someService;
Name = "Slim Shady";
Execute();
}
public string Name
{
get
{
return _personService.Name;
}
set
{
_personService.Name = value;
OnPropertyChanged();
}
}
private void Execute()
{
string dupa = _someService.GetTheName(_personService);
System.Windows.MessageBox.Show(dupa);
System.Windows.MessageBox.Show(Name);
}
}
我有一个解决方案,它使用 Autofac,并且我将一些方法从我的视图模型移到了服务文件中。现在我面临一个问题,服务方法中的一些变量引用了 VM 属性。所以我想通了,也许我应该将视图模型传递给服务。
首先,为了层分离和可测试性,我不确定我是否应该这样做。不过我猜的,mocking应该是没问题的,不对请指正
另一件事是我还不确定如何将虚拟机传递给服务。使用我当前的解决方案,您可以在下面找到,我在 Model 道具的 setter 上遇到 Whosebug
异常。问题是,现在这是我拥有的最好的,我没有任何新想法。
另一件事,如果将 VM 传递到服务层是一种反模式,我应该如何从服务层引用 VM 属性?我是否应该为此创建一些包装器,VM 和服务将引用它?
代码将在简化示例中显示。 MainViewModel:
public class MainViewModel : ViewModelBase
{
private MainViewModel _vm;
private Person _person;
private ISomeService _someService;
public MainViewModel(ISomeService someService)
{
_person = new Person();
_someService = someService;
Name = "Slim Shady";
_vm = new MainViewModel(_someService);
Execute();
}
public string Name
{
get
{
return _person.Name;
}
set
{
_person.Name = value;
OnPropertyChanged();
}
}
private void Execute()
{
string dupa = _someService.GetTheName(_vm);
System.Windows.MessageBox.Show(dupa);
}
}
型号:
public class Person
{
public string Name { get; set; }
}
服务:
public interface ISomeService
{
string GetTheName(ViewModel.MainViewModel _vm);
}
public class SomeService : ISomeService
{
public string GetTheName(MainViewModel _vm)
{
return _vm.Name;
}
}
Autofac:
public class BootStrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<SomeService>()
.As<ISomeService>().SingleInstance();
builder.RegisterType<MainWindow>().AsSelf();
builder.RegisterType<MainViewModel>().AsSelf().SingleInstance();
return builder.Build();
}
}
更新 还需要考虑一些其他服务也会引用 Person.
的 Name 属性 的情况我认为这里存在责任倒置。
如果您的服务必须产生数据,它必须保存这些数据。这不是 VM 的工作。
因此,在您的示例中,Name 是 Person 的 属性,并且反过来成为您 VM 中 getter 方法的结果。
我不知道 Autofac,但我认为您的服务应该持有 Person 对象,并将其提供给 VM(通过 IoC)。
不过,我们仍然缺少上下文信息以获取完整且合适的答案。
如果 Person 需要在 VM 中实例化,您可以简单地在 VM 中告诉您的服务实例化它,然后 return 它:
public MainViewModel(ISomeService someService)
{
_someService = someService;
_person = _someService.GetPerson("John");
//etc
}
public interface ISomeService
{
Person GetPerson(string name);
}
public class SomeService : ISomeService
{
private List<Person> personRepository;
//insert constructor...
public Person GetPerson(string name)
{
return personRepository.Single(person => person.Name == name);
}
}
简而言之,服务不应该知道 VM,甚至不应该知道 VM 是什么。
Should I pass View Model to my service, and if yes, how to do it?
不,你不应该。服务不应该对视图模型有任何依赖性。正好相反。
Another thing, if passing a VM to the Service layer is an antipattern, how should I refer a VM property from the Service layer?
你不知道。该服务应该 return 视图模型可能需要的任何数据,但它不应该知道任何关于视图模型类型本身的信息。
在您的示例中,服务应该只是 return 一个字符串:
public string GetTheName()
{
return "...";
}
如果这个字符串来自视图模型,那么首先使用服务来检索它是没有意义的。然后您可以直接在视图模型 class 中访问 this.Name
。
如果服务以某种方式操纵名称 string
,它应该接受 string
作为参数和 return 另一个字符串,例如:
public string GetTheName(string name)
{
return name.Trim();
}
最终解决方案
在我创建的服务层中:
public interface IPersonService
{
string Name { get; set; }
}
public class PersonService : IPersonService
{
Person _personModel = new Person();
public string Name
{
get
{
return _personModel.Name;
}
set
{
_personModel.Name = value;
}
}
}
并修改:
public interface ISomeService
{
string GetTheName(IPersonService personService);
}
public class SomeService : ISomeService
{
public string GetTheName(IPersonService personService)
{
return personService.Name;
}
}
所以现在我将两种服务都注入到我的 VM 中,当从 SomeService
中检索名称时,我正在通过注入 PersonServie
:
public class MainViewModel : ViewModelBase
{
private IPersonService _personService;
private ISomeService _someService;
public MainViewModel(ISomeService someService, IPersonService personService)
{
_personService = personService;
_someService = someService;
Name = "Slim Shady";
Execute();
}
public string Name
{
get
{
return _personService.Name;
}
set
{
_personService.Name = value;
OnPropertyChanged();
}
}
private void Execute()
{
string dupa = _someService.GetTheName(_personService);
System.Windows.MessageBox.Show(dupa);
System.Windows.MessageBox.Show(Name);
}
}