通过界面/工厂填充集合?

时间:2012-10-11 16:24:44

标签: c# factory-pattern

我使用的模式是将实现接口的具体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,那么存储库可以获得集合并以无效方式修改它。我认为这些事情很少发生,因为团队会知道这种模式,但总是没有陷阱总是很好,而不是在那里陷入陷阱,每个人都必须记住不要介入。

实际上,感觉有点脏。

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

1 个答案:

答案 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,它就会变得更有问题。