設計模式-規約模式C#版
規約模式的使用場景就是規則,業務規則的碎片化。
業務規則的組合是不固定的,需要做成很容易組合,也很容易拆散的方式,規約模式是一個選擇。
下面的例子是一個書店中,用戶租書的場景。
需要判斷用戶的最大租書數和用戶的狀態,需要同時滿足這兩個要求,才可以繼續租書。最大租書數和狀態這兩個規則拆散開來,在需要的時候再進行組合。不需要組合的地方,就單獨使用這些規則。
針對一個實體有不同的規則,把這些規則碎片化,隨意組合和拆散,這樣就構成了規約模式。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DomainModel.Model
{
/// <summary>
/// 規約模式
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ISpecification<T>
{
bool IsSatisfiedBy(T entity);
/// <summary>
/// 與規約
/// </summary>
/// <param name="specification"></param>
/// <returns></returns>
ISpecification<T> And(ISpecification<T> specification);
/// <summary>
/// 或規約
/// </summary>
/// <param name="specification"></param>
/// <returns></returns>
ISpecification<T> Or(ISpecification<T> specification);
/// <summary>
/// 非規約
/// </summary>
/// <returns></returns>
ISpecification<T> Not();
}
public class Customer
{
private ISpecification<Customer> _hasReachedMax;
private ISpecification<Customer> _active;
public Customer(ISpecification<Customer> hasReachedMax, ISpecification<Customer> active)
{
this._hasReachedMax = hasReachedMax;
this._active = active;
}
public int TotalRentNumber { get; set; }
public bool Active
{
get { return true; }
}
public bool CanRent()
{
var specification = this._hasReachedMax.Not().And(this._active.Not());
return specification.IsSatisfiedBy(this);
}
}
public class HasReachedMaxSpecification : CompositeSpecification<Customer>
{
public override bool IsSatisfiedBy(Customer entity)
{
return entity.TotalRentNumber >= 6;
}
}
public class CustomerActiveSpecification : CompositeSpecification<Customer>
{
public override bool IsSatisfiedBy(Customer entity)
{
return entity.Active;
}
}
/// <summary>
/// 組合規約
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class CompositeSpecification<T> : ISpecification<T>
{
public abstract bool IsSatisfiedBy(T entity);
public ISpecification<T> And(ISpecification<T> specification)
{
return new AndSpecification<T>(this, specification);
}
public ISpecification<T> Not()
{
return new NotSpecification<T>(this);
}
public ISpecification<T> Or(ISpecification<T> specification)
{
throw new NotImplementedException();
}
}
public class AndSpecification<T> : CompositeSpecification<T>
{
private ISpecification<T> _left;
private ISpecification<T> _right;
public AndSpecification(ISpecification<T> left, ISpecification<T> right)
{
this._left = left;
this._right = right;
}
public override bool IsSatisfiedBy(T entity)
{
return this._left.IsSatisfiedBy(entity) && this._right.IsSatisfiedBy(entity);
}
}
public class OrSpecification<T> : CompositeSpecification<T>
{
private ISpecification<T> _left;
private ISpecification<T> _right;
public OrSpecification(ISpecification<T> left, ISpecification<T> right)
{
this._left = left;
this._right = right;
}
public override bool IsSatisfiedBy(T entity)
{
return this._left.IsSatisfiedBy(entity) || this._right.IsSatisfiedBy(entity);
}
}
public class NotSpecification<T> : CompositeSpecification<T>
{
private ISpecification<T> _inner;
public NotSpecification(ISpecification<T> inner)
{
this._inner = inner;
}
public override bool IsSatisfiedBy(T entity)
{
return !this._inner.IsSatisfiedBy(entity);
}
}
}