活动记录与存储库 - 利弊 [英] Active Records vs. Repository - pros and cons?

查看:197
本文介绍了活动记录与存储库 - 利弊的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用ActiveRecord可以定义一个这样的类:

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

public Boolean验证(){... / *检查名称在DB * /中是唯一的

public Boolean保存( ){...}

public static List< Contact> Load(){...}
}

虽然这很好,简单,发现我的课程变得非常blo肿,大量的逻辑正在进行!



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

 类联系
{
[必需(AllowEmptyStrings = false)]
public String Name {get;组; }
}

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()
}
}

class ContactRepository:IRepository
{
public List< Contact> GetAll(){...}
public Contact GetById(int Id){...}
public Boolean保存(联系联系人){...}
}

class ContactValidator:IValidator
{
public Boolean验证(联系联系人){... / *检查名称在DB * / $中是唯一的
}

class UnitOfWork:IUnitOfWork
{
IRepository _contacts = null;
public UnitOfWork(IRepository contacts){_contacts = contacts; }
public Commit(){_contacts.Save(); }
}

如何从Active Record =>分层设计迁移? >


  • 名称设置器中的实体级别验证=>保留(可以通过DataAnnotation获取)

  • 业务逻辑/规则验证(唯一名称)=>从实体移动到新的单独的ContactValidator

  • 将逻辑=>移动到单独的存储库模式类(也可以是UnitOfWork)

  • 加载逻辑=>移动到单独的存储库

  • 与存储库的交互是通过一个新的ContactService(它将强制使用ContactValidator,ContactRepository,UnitOfWork等 - 反对让调用者与ContactRepository一起使用!)。



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



NB - 这个例子是故意简单的(UnitOfWork并没有被真正使用,并且Repository / Validator的新增将被不同的处理)。 >

解决方案

这真的取决于你的域逻辑的复杂程度。例如,如果我正在写一个简单的博客,那么活动记录将会很好,大多数应用程序正在保存和加载数据。它的简单和活跃的记录模式是正确的工作。



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



使用域驱动的设计,您将使用规格模式实现您的验证。


Using ActiveRecord you might define a class like this:

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() { ... }
}

Whilst this is nice and simple, I've found my classes become very bloated with a big mix of logic going on!

Using a layered/domain design you might define the same class like:

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(); }
}

How was it migrated from Active Record => layered design?

  • Entity level validation in the Name setter => remains (ableit via a DataAnnotation)
  • Business logic/rule validation (unique Name) => moved from entity into a new separate ContactValidator
  • Save logic => moved to a separate Repository pattern class (also with a UnitOfWork)
  • Load logic => moved to the separate Repository
  • Interaction with the Repository is via a new ContactService (which will enforce use of ContactValidator, ContactRepository, UnitOfWork, etc - opposed to letting the caller loose with the ContactRepository!).

I'm looking for peer approval/suggestions for this layered design - I don't usually design outside of Active Record type! Any comment appreciated.

NB - This example is deliberately simple (the UnitOfWork isn't really used and the newing of Repository/Validator would be handled differently).

解决方案

It really depends on how complex your domain logic is. For example if I was writing a simple blog then active record will be fine, mostly the application is saving and loading data. Its simple and active record pattern is the right tool for the job.

However if I was writing software for a shipping company in which there are many complex business rules and processes then using the repository pattern, along with other Domain Driven Design patterns will provide at much more maintainable code in the long run.

Using domain driven design you would use the specification pattern to achieve your validation.

这篇关于活动记录与存储库 - 利弊的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆