标签:err 对象 back ring rem cte 规范 logic feedback
原文: Applied Domain-Driven Design (DDD), Part 3 - Specification Pattern
Specification pattern is great, David Fancher wrote a great piece on it, i suggest you read it before you continue.
规范模式十分强大, David Fancher 了一篇非常好的关于规范模式的文章, 我建议你在阅读本文之前去读一下那篇文章.
In short, specification pattern allows you to chain business queries.
简而言之, 规范模式就是允许你可以链式业务查询.
ISpecification<Customer> spec =
new CustomerRegisteredInTheLastDays(30).And(new CustomerPurchasedNumOfProducts(2));
public class Customer : IDomainEntity
{
private List<Purchase> purchases = new List<Purchase>();
public Guid Id { get; protected set; }
public string FirstName { get; protected set; }
public string LastName { get; protected set; }
public string Email { get; protected set; }
public string Password { get; protected set; }
public DateTime Created { get; protected set; }
public bool Active { get; protected set; }
public ReadOnlyCollection<Purchase> Purchases { get { return this.purchases.AsReadOnly(); } }
public static Customer Create(string firstname, string lastname, string email)
{
Customer customer = new Customer()
{
FirstName = firstname,
LastName = lastname,
Email = email,
Active = true,
Created = DateTime.Today
};
DomainEvents.Raise<CustomerCreated>(new CustomerCreated() { Customer = customer });
return customer;
}
public Purchase Checkout(Cart cart)
{
Purchase purchase = Purchase.Create(this, cart.Products);
this.purchases.Add(purchase);
DomainEvents.Raise<CustomerCheckedOut>(new CustomerCheckedOut() { Purchase = purchase });
return purchase;
}
}
public class CustomerRegisteredInTheLastDays : SpecificationBase<Customer>
{
readonly int nDays;
public CustomerRegisteredInTheLastDays(int nDays)
{
this.nDays = nDays;
}
public override Expression<Func<Customer,bool>> SpecExpression
{
get
{
return customer => customer.Created >= DateTime.Today.AddDays(-nDays)
&& customer.Active;
}
}
}
public class CustomerPurchasedNumOfProducts : SpecificationBase<Customer>
{
readonly int nPurchases;
public CustomerPurchasedNumOfProducts(int nPurchases)
{
this.nPurchases = nPurchases;
}
public override Expression<Func<Customer,bool>> SpecExpression
{
get
{
return customer => customer.Purchases.Count == this.nPurchases
&& customer.Active;
}
}
}
IRepository<Customer> customerRepository = new Repository<Customer>();
ISpecification<Customer> spec =
new CustomerRegisteredInTheLastDays(30).And(new CustomerPurchasedNumOfProducts(2));
IEnumerable<Customer> customers = customerRepository.Find(spec);
public interface IRepository<TEntity>
where TEntity : IDomainEntity
{
TEntity FindById(Guid id);
TEntity FindOne(ISpecification<TEntity> spec);
IEnumerable<TEntity> Find(ISpecification<TEntity> spec);
void Add(TEntity entity);
void Remove(TEntity entity);
}
- Specification allows you to query data in a abstract way i.e. you can query memory collections or an RDBMS. This ensures persistence/infrastructure ignorance.
- Specification encapsulates a business rule in one spec.
- Specification pattern allows you to chain your business rules up.
- Specification makes your domain layer DRY i.e. you don‘t need to write same LINQ all over again.
- Specifications are easy to unit test.
- Specifications are stored in the domain layer, this provides full visibility.
- Specifications are super elegant.
- Break complex business logic rules down in your specification as NHibernate might struggle to interpret them in to a SQL query. This is a generally good tip as you don‘t want messy SQL hitting your database.
- Query data around the entity properties, don‘t try and change the properties on the entity i.e. instead of writing customer.Created.AddDays(30) >= DateTime.Today write customer.Created >= DateTime.Today.AddDays(-30). The former will try and compile it as a SQL and will fail as it‘s too complex, the latter will convert the value to a parameter.
customer.Created >= DateTime.Today.AddDays(-30)
代替 customer.Created.AddDays(30) >= DateTime.Today
. 后者可能因为太复杂导致尝试编译为 SQL 语句而失败, 前者则会把值转化为参数.
- As specifications are logical queries they should not change state of the caller or the calling objects. i.e. don‘t call state changing methods, such as customer.Checkout(....) && customer.Active == true. This tip goes hand in hand with the tip above.
customer.Checkout(....) && customer.Active == true
修改状态的方法. 这个建议与上面的建议是相辅相成的.*Note: Code in this article is not production ready and is used for prototyping purposes only. If you have suggestions or feedback please do comment.
*注意: 本文中的代码尚未准备好投入生产, 仅用于原型设计. 如果有建议和反馈, 请发表评论.
标签:err 对象 back ring rem cte 规范 logic feedback
原文地址:https://www.cnblogs.com/xixixiao/p/applied-domain-driven-design-ddd-part-3.html