Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Most of the times it is best to place these kind of rules in <code>Specification</code> objects. You can place these <code>Specification</code>s in your domain packages, so anybody using your domain package has access to them. Using a specification, you can bundle your business rules with your entities, without creating difficult-to-read entities with undesired dependencies on services and repositories. If needed, you can inject dependencies on services or repositories into a specification.</p> <p>Depending on the context, you can build different validators using the specification objects.</p> <p>Main concern of entities should be keeping track of business state - that's enough of a responsibility and they shouldn't be concerned with validation. </p> <p><em>Example</em></p> <pre><code>public class User { public string Id { get; set; } public string Name { get; set; } } </code></pre> <p>Two specifications:</p> <pre><code>public class IdNotEmptySpecification : ISpecification&lt;User&gt; { public bool IsSatisfiedBy(User subject) { return !string.IsNullOrEmpty(subject.Id); } } public class NameNotTakenSpecification : ISpecification&lt;User&gt; { // omitted code to set service; better use DI private Service.IUserNameService UserNameService { get; set; } public bool IsSatisfiedBy(User subject) { return UserNameService.NameIsAvailable(subject.Name); } } </code></pre> <p>And a validator:</p> <pre><code>public class UserPersistenceValidator : IValidator&lt;User&gt; { private readonly IList&lt;ISpecification&lt;User&gt;&gt; Rules = new List&lt;ISpecification&lt;User&gt;&gt; { new IdNotEmptySpecification(), new NameNotEmptySpecification(), new NameNotTakenSpecification() // and more ... better use DI to fill this list }; public bool IsValid(User entity) { return BrokenRules(entity).Count() &gt; 0; } public IEnumerable&lt;string&gt; BrokenRules(User entity) { return Rules.Where(rule =&gt; !rule.IsSatisfiedBy(entity)) .Select(rule =&gt; GetMessageForBrokenRule(rule)); } // ... } </code></pre> <p>For completeness, the interfaces:</p> <pre><code>public interface IValidator&lt;T&gt; { bool IsValid(T entity); IEnumerable&lt;string&gt; BrokenRules(T entity); } public interface ISpecification&lt;T&gt; { bool IsSatisfiedBy(T subject); } </code></pre> <p><em>Notes</em></p> <p>I think Vijay Patel's earlier answer is in the right direction, but I feel it's a bit off. He suggests that the user entity depends on the specification, where I belief that this should be the other way around. This way, you can let the specification depend on services, repositories and context in general, without making your entity depend on them through a specification dependency.</p> <p><em>References</em></p> <p>A related question with a good answer with example: <a href="https://stackoverflow.com/questions/516615/validation-in-a-domain-driven-design">Validation in a Domain Driven Design</a>.</p> <p>Eric Evans describes the use of the specification pattern for validation, selection and object construction in <a href="http://my.safaribooksonline.com/book/software-engineering-and-development/0321125215/making-implicit-concepts-explicit/145" rel="nofollow noreferrer">chapter 9, pp 145</a>.</p> <p>This <a href="http://devlicio.us/blogs/casey/archive/2009/03/02/ddd-the-specification-pattern.aspx" rel="nofollow noreferrer">article on the specification pattern</a> with an application in .Net might be of interest to you.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload