我使用的模式是将实现接口的具体ViewModel传递给存储库,然后存储库填充ViewModel对象,但仅使用该接口。这使得存储库变得更重,但允许存储库在不同的场景中重用。例如,具体实现可以是MVC ViewModel,也可以是实现接口的asp.net Page,其中每个proeprty的set访问器实际上将值放入GUI,例如文本框。接口的实现用作映射并消除了额外的复制步骤。在广泛使用了AutoMapper之后,我现在更喜欢这种模式。
public interface IPerson
{
int Id{set};
string Name{set};
string Address{set};
}
public class PersonRepository
{
GetPerson(int id, IPerson person)
{
//query...
person.Id = result.Id;
person.Name = result.Name;
person.Address = result.Address;
}
}
//...controller action
PersonViewModel person = new PersonViewModel();
rep.GetPerson(5, person);
虽然这是棘手的部分。有时,ViewModel需要一组项目,可以是索引页面,也可以是下拉列表,或者显示一组嵌套的子对象。存储库无法实例化接口,因此我们提供它是一个工厂。在与协方差斗争了一段时间后,我放弃了暴露任何类型的集合,最终得到了一个创建和添加集合项的方法:
public interface IPerson
{
//...
IJobRole CreateAndAddJobRole();
}
public class PersonViewModel:IPerson
{
//collection not part of the interface
ICollection<JobRoles> JobRoles {get;set;} //= new List<JobRoles> in constructor
public CreateAndAddJobRole()
{
role = new JobRole();
JobRoles.Add(role);
return role;
}
}
public class PersonRepository
{
GetPerson(int id, IPerson person)
{
//...
foreach(var result...)
{
IJobRole role = person.CreateAndAddJobRole();
role.SomeProperty = //...
}
}
}
显然,我可能有处理作业角色的存储库实际上是填充集合的存储库。我可能实际上有更细粒度的接口,因此不同的存储库将负责填充它们处理的数据。 ViewModel只需实现多个接口。也就是说,我意识到还有改进的余地,但我特地在这里是因为我对处理收集问题没有任何好的想法。
此设计的一个好处是没有暴露的集合可能被存储库滥用。永远不会猜测谁负责实例化集合本身,或者谁填充它,或者如果你只是一个getter,那么存储库可以获得集合并以无效方式修改它。我认为这些事情很少发生,因为团队会知道这种模式,但总是没有陷阱总是很好,而不是在那里陷入陷阱,每个人都必须记住不要介入。
实际上,感觉有点脏。
当这样做的方法只知道接口时,您如何设计/公开具体类型实例化并添加到集合的能力?
答案 0 :(得分:1)
听起来你最好的选择是让每个界面都是通用的,并传递集合的类型。例如:
public interface IPerson<TJob> where TJob : IJobRole
{
ICollection<TJob> JobRoles {get;set;}
void AddJobRole(TJob role);
}
public JobRole : IJobRole
{
}
public class PersonViewModel:IPerson<JobRoles>
{
//collection is now part of the interface
ICollection<JobRoles> JobRoles //= new List<JobRoles> in constructor
public void AddJobRole(JobRoles role)
{
JobRoles.Add(role);
}
}
public class PersonRepository
{
GetPerson(int id, IPerson<JobRoles> person)
{
//...
foreach(var result...)
{
person.AddJobRole(new JobRole {
SomeProperty = //...
SomeOther = //...
}
}
}
}
当然,这假设您在致电IPerson<>
时知道所需的GetPerson()
类型。但是,如果你需要它来处理那里的任何IPerson
,它就会变得更有问题。