1

我正在使用一种模式,其中实现接口的具体 ViewModel 被传递到存储库,然后填充 ViewModel 对象,但仅使用接口。这使得存储库更重一些,但允许在不同场景中重用存储库。例如,具体实现可以是 MVC ViewModel,也可以是实现接口的 asp.net Page,其中每个属性的 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,存储库可以获取集合并以无效的方式对其进行修改。我认为这些情况很少见,因为团队会知道这种模式,但是完全没有陷阱总是很好的,而不是每个人都必须记住不要介入的陷阱。

事实上,它感觉有点脏。

当这样做的方法只知道接口时,您将如何设计/公开将具体类型实例化并添加到集合中的能力?

4

1 回答 1

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那里的任何东西,它就会变得更加成问题。

于 2012-10-11T17:44:53.203 回答