Active Records vs. Repository - 优点和缺点?

Mat*_*att 10 activerecord design-patterns architectural-patterns

使用ActiveRecord,您可以定义这样的类:

class Contact
{
  private String _name;
  public String Name
  {
    get { return _name; }
    set 
    { 
      if (value == String.IsNullOrWhiteSpace())
        throw new ArgumentException(...);
      else
        _name = value;
    }
  }

  public Boolean Validate() { ... /* check Name is unique in DB */  }

  public Boolean Save() { ... }

  public static List<Contact> Load() { ... }
}
Run Code Online (Sandbox Code Playgroud)

虽然这很简单,但我发现我的课程变得非常臃肿,伴随着大量的逻辑组合!

使用分层/域设计,您可以定义相同的类,如:

class Contact
{
    [Required(AllowEmptyStrings=false)]
    public String Name { get; set; }
}

class ContactService : IService
{
    public List<Contact> LoadContacts() { return (new ContactRepository()).GetAll(); }
    public Contact LoadContact(int id) { return (new ContactRepository()).GetById(id); }
    public Boolean SaveContact(Contact contact)
    {
        if (new ContactValidator().Validate(contact))
            new ContactRepository().Save(contact);
    }
}

class ContactRepository : IRepository
{
    public List<Contact> GetAll() { ... }
    public Contact GetById(int Id) { ... }
    public Boolean Save(Contact contact) { ... }
}

class ContactValidator : IValidator
{
    public Boolean Validate(Contact contact) { ... /* check Name is unique in DB */ }
}

class UnitOfWork : IUnitOfWork
{
    IRepository _contacts = null;
    public UnitOfWork(IRepository contacts) { _contacts = contacts; }
    public Commit() { _contacts.Save(); }
}
Run Code Online (Sandbox Code Playgroud)

它是如何从Active Record =>分层设计迁移出来的?

  • Name setter =>中的实体级别验证仍然存在(能够通过DataAnnotation)
  • 业务逻辑/规则验证(唯一名称)=>从实体移动到新的单独ContactValidator
  • 保存逻辑=>移动到单独的存储库模式类(也使用UnitOfWork)
  • 加载逻辑=>移动到单独的存储库
  • 与存储库的交互是通过一个新的ContactService(它将强制使用ContactValidator,ContactRepository,UnitOfWork等 - 而不是让调用者通过ContactRepository松散!).

我正在为这种分层设计寻找同行批准/建议 - 我通常不会在Active Record类型之外进行设计!任何评论赞赏.

注意 - 这个例子是故意简单的(UnitOfWork并没有真正使用,而且Repository/Validator的新版本将以不同的方式处理).

g.f*_*ley 7

这实际上取决于您的域逻辑的复杂程度.例如,如果我正在编写一个简单的博客,那么活动记录就可以了,主要是应用程序正在保存和加载数据.其简单而活跃的记录模式是适合该工作的正确工具.

但是,如果我为运输公司编写软件,其中有许多复杂的业务规则和流程,那么使用存储库模式,以及其他领域驱动设计模式将在长期内提供更多可维护的代码.

使用域驱动设计,您将使用规范模式来实现验证.


oll*_*cua 7

这篇文章似乎对两者都有很好而简洁的描述: https://hashnode.com/post/which-design-pattern-do-you-prefer-active-record-or-repository-cilozoaa5016o6t53mhsdu6nu

我想补充的一件事是,它不仅仅是“当您的持久性需求简单时,活动记录很好;当您的持久性需求复杂时,存储库很好”。这里图案的选择更多地与你对德墨忒尔定律的感受有关。如果您希望架构的不同部分完全分离,以便某人可以理解一个部分而不理解另一个部分,那么您需要德墨忒尔定律。也就是说,我认为,特别是在项目的早期,当规范可能发生变化时,过于痴迷于这些抽象是非常危险的。不要再猜测你的项目未来的维护者,他们可能很聪明,他们应该能够一次考虑不止一件事,如果他们不能,那么你可能会遇到使用存储库模式无法避免的更大问题。


And*_*lov 5

两种方法都有其优点和缺点。

假设您正在将 Active Record 样式的对象传递到某个地方(BL 深处)。你可以阅读它,你可以改变它,你可以保存它。在这种情况下,那块 BL 仅与您实体的接口耦合。使用分层架构,您必须以某种方式将存储库传递给该代码。您可以显式传递它或使用 IoC 容器 - 由您决定。

另一点是,当您有了存储库的概念时,您可以轻松定义诸如“we-have-a-new-object-in-repository”或“one-object-has-been-deleted-from-repository”之类的概念,这些概念基本上是如果您正在使用分布式环境,那么这是非常有用的通知。