4

我试图了解丰富的域模型以及如何将语义功能构建到域实体中,其中域实体没有与提供语义行为实现的对象紧密耦合

例如,我想在User我的域模型中构建一个实体,但我希望它的实现由身份框架驱动

class User
{
    public string Email { get; set; }
    ... All of the other IdentityUser properties...

    public void DisableUser()
    {
        ...behaviour to disable a user, most likely requires UserManager
    }

    public void AddToRole(Role role)
    {
        ... most likely requires RoleManager
    }
}

所以现在我有一个根据业务规则运行的域模型,并且对持久性和实现一无所知。

但是,当它们没有依赖关系并且不以任何方式与 and 耦合时,它们究竟DisableUser()应该AddToRole()如何UserManager工作RoleManager

  • 一般来说,我错过了什么?
  • 域实体是否应该依赖于提供行为的对象?
  • 我应该如何将我的域模型与实现提供者分离?
4

2 回答 2

0

我所做的是让我的每个富域模型实体都接收对中央域对象的引用作为构造函数参数,并将其存储为readonly成员。

这很容易,因为域充当其实体的工厂,因此只要它是其中之一,它就会作为第一个构造函数参数new传递。this(实体应该具有程序集内部的构造函数,以便它们不能被除域本身之外的任何人实例化。)

如果你真的深入研究 ORM 框架的文档,你通常会发现它们往往允许你为你的实体提供一个工厂,所以你可以做这样的事情。

因此,由于每个实体都有对域的引用,因此它可以从它那里获得完成其工作所需的任何东西。(大概,您的域对象将包含对 aUserManager和a 的引用RoleManager,不是吗?)这实质上是从依赖注入中退后一步:您注入域对象及其依赖项,但是您让域的每个实体获取它的来自域对象的依赖项。

这是java中的一个例子:

package ...
import ...

public final class StarWarsDomain extends Domain
{
    private static final Schema SCHEMA = ...

    public StarWarsDomain( LogicDomain logicDomain, S2Domain delegeeDomain )
    {
        super( logicDomain, SCHEMA, delegeeDomain ); //these get stored in final members of 'Domain'
    }

    public UnmodifiableEnumerable<Film> getAllFilms()
    {
        return getAllEntitys( Film.COLONNADE ); //method of 'Domain'
    }

    public Film newFilm( String name )
    {
        assert !StringHelpers.isNullOrEmptyOrWhitespace( name );
        Film film = addEntity( Film.COLONNADE ); //method of 'Domain'
        film.setName( name );
        return film;
    }
}
于 2016-10-14T19:18:44.790 回答
0

精心设计的领域模型不应依赖于任何其他架构层或服务。就我而言,域模型对象应该是(在我的情况下) POCOs (Plain Old CLR Objects)。诸如业务逻辑或持久层之类的服务和层应该依赖于这些对象并返回它们的实例。

建立一个尊重低耦合、高内聚和持久性无知的领域模型有几个关键。在一个声明中,秘诀是“编写你希望拥有的代码”。

领域模型示例

public class Student
{
    // Collections should be encapsulated!
    private readonly ICollection<Course> courses;

    // Expose constructors that express how students can be created.
    // Notice that this constructor calls the default constructor in order to initialize the courses collection.
    public Student(string firstName, string lastName, int studentNumber) : this()
    {
        FirstName = firstName;
        LastName = lastName;
        StudentNumber = studentNumber;
    }

    // Don't allow this constructor to be called from code.
    // Your persistence layer should however be able to call this via reflection.
    private Student()
    {
        courses = new List<Course>();
    }

    // This will be used as a primary key. 
    // We should therefore not have the ability to change this value. 
    // Leave that responsibility to the persistence layer.
    public int Id { get; private set; }

    // It's likely that students names or numbers won't change, 
    // so set these values in the constructor, and let the persistence 
    // layer populate these fields from the database.
    public string FirstName { get; private set; }
    public string LastName {get; private set; }
    public int StudentNumber { get; private set; }

    // Only expose courses via something that is read-only and can only be iterated over.
    // You don't want someone overwriting your entire collection.
    // You don't want someone clearing, adding or removing things from your collection.
    public IEnumerable<Course> Courses => courses;

    // Define methods that describe semantic behaviour for what a student can do.
    public void Subscribe(Course course)
    {
        if(courses.Contains(course))
        {
            throw new Exception("Student is already subscribed to this course");
        }

        courses.Add(course);
    }

    public void Ubsubscribe(Course course)
    {
        courses.Remove(course);
    }
}

当然,这个域模型对象是在考虑实体框架的情况下编写的,但它与通常的实体框架示例(相比之下,它们是贫乏的域模型)相去甚远。以这种方式制作域模型对象时需要考虑一些注意事项,但 Entity Framework 将持久保存它们(带有一点点诡计),并且您会得到一个域模型对象,该对象定义了一个干净的语义契约到层这取决于它。

于 2017-02-14T11:52:26.567 回答