Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 了解丰富的领域模型和依赖关系_C#_Asp.net Identity_Domain Model_Rich Domain Model - Fatal编程技术网

C# 了解丰富的领域模型和依赖关系

C# 了解丰富的领域模型和依赖关系,c#,asp.net-identity,domain-model,rich-domain-model,C#,Asp.net Identity,Domain Model,Rich Domain Model,我试图了解丰富的域模型,以及如何将语义功能构建到域实体中,域实体与提供语义行为实现的对象之间没有紧密耦合 例如,我想在我的域模型中构建一个用户实体,但我希望它的实现由identity框架驱动 class User { public string Email { get; set; } ... All of the other IdentityUser properties... public void DisableUser() { ...beh

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

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

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
    }
}
现在,我有了一个域模型,它根据业务规则运行,对持久性和实现一无所知

但是,如果
DisableUser()
AddToRole()
没有依赖关系,并且不以任何方式与
UserManager
rolemager
耦合,那么它们到底应该如何工作呢

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

我要做的是让我的每个富域模型实体接收对中心域对象的引用作为构造函数参数,并将其存储为
只读成员

这很容易,因为域充当其实体的工厂,因此每当它
新建
其中一个实体时,它都将
作为第一个构造函数参数传递。(实体应该具有程序集内部构造函数,因此除了域本身之外,任何人都不能实例化它们。)

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

因此,因为每个实体都有一个对域的引用,所以它可以从域中获得它所需要的任何工作。(想必,您的域对象将包含对
UserManager
rolemanger
,否?)这实际上是从依赖项注入中后退了一步:您将域对象与其依赖项一起注入,但您让域的每个实体从域对象获取其依赖项

以下是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;
    }
}
包。。。
导入。。。
公共最终类StarWarsDomain扩展域
{
私有静态最终架构=。。。
公共StarWarsDomain(LogicDomain LogicDomain、S2Domain DelegeDomain)
{
super(logicDomain、SCHEMA、DelegeDomain);//这些存储在“域”的最终成员中
}
公共不可修改可枚举getAllFilms()
{
返回getAllEntitys(Film.COLONNADE);//域的方法
}
公共电影newFilm(字符串名称)
{
assert!StringHelpers.isNullOrEmptyOrWhitespace(名称);
Film-Film=addEntity(Film.COLONNADE);//域的方法
电影集名(名称);
回流膜;
}
}

精心设计的域模型不应依赖于任何其他体系结构层或服务。关于这一点,域模型对象应该是(在我的例子中)POCOs(普通的旧CLR对象)。服务和层(如业务逻辑或持久性层)应该依赖于这些对象并返回它们的实例

构建一个低耦合、高内聚和持久性的领域模型有几个关键点。在一句话中,其中的秘诀是“编写你希望拥有的代码”

域模型示例

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);
    }
}
公共班级学生
{
//集合应该被封装!
私人只读的ICollection课程;
//公开表示如何创建学生的构造函数。
//请注意,此构造函数调用默认构造函数以初始化courses集合。
公共学生(stringfirstname、stringlastname、int studentNumber):this()
{
名字=名字;
LastName=LastName;
StudentNumber=StudentNumber;
}
//不允许从代码调用此构造函数。
//然而,您的持久性层应该能够通过反射来调用它。
私立学生()
{
课程=新列表();
}
//这将用作主键。
//因此,我们不应该有能力改变这个值。
//将这一责任留给持久性层。
public int Id{get;private set;}
//学生的名字或数字很可能不会改变,
//因此,在构造函数中设置这些值,并让持久性
//图层从数据库填充这些字段。
公共字符串名{get;private set;}
公共字符串LastName{get;private set;}
public int StudentNumber{get;private set;}
//仅通过只读且只能迭代的内容公开课程。
//你不希望有人覆盖你的整个收藏。
//你不希望有人清理、添加或删除你收藏中的物品。
公共IEnumerable课程=>课程;
//定义描述学生语义行为的方法。
公众假期订阅(课程)
{
if(课程。包含(课程))
{
抛出新异常(“学生已订阅此课程”);
}
课程。添加(课程);
}
公开无效认购(课程)
{
课程。移除(课程);
}
}

诚然,这个领域模型对象是在考虑实体框架的情况下编写的,但它与通常的实体框架示例(相比之下,它们是贫乏的领域模型)相差甚远。在以这种方式构建域模型对象时,需要考虑一些注意事项,但Entity Framework会将它们持久化(有一点诡计),您会得到一个定义干净,语义收缩到依赖它的层。

当我这样做时,我称我的富领域模型实体为主题,而面向领域编程的一般方法论是