领域驱动设计,领域对象,对二传手的态度 [英] Domain Driven Design, Domain objects, attitude about Setters

查看:170
本文介绍了领域驱动设计,领域对象,对二传手的态度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在看一些Greg Young的视频最近,我试图理解为什么会出现对二传手的领域对象持否定态度。我以为域对象被认为是重与DDD的逻辑。是否有良好的例子在线坏榜样,然后自己的方式来纠正呢?任何例子或者解释是不错的。这是否只适用于存储在CQRS的方式活动或者这是否适用于所有DDD的?

Been watching some Greg Young videos lately and I'm trying to understand why there is a negative attitude towards Setters on Domain objects. I thought Domain objects were supposed to be "heavy" with logic in DDD. Are there any good examples online of the bad example and then they way to correct it? Any examples or explanations are good. Does this only apply to Events stored in a CQRS manner or does this apply to all of DDD?

推荐答案

我造成这个答案补充约不变量与其他原因罗杰Alsing答案。

I'm contributing this answer to complement Roger Alsing answer about invariants with other reasons.

语义信息

罗杰解释清楚,物业制定者不携带语义信息。允许二传手像Post.PublishDate属性可以增加混乱,因为我们无法知道是否该职位已经公布或者只有在发布日期尚未确定。我们不能肯定知道,这是所有需要发布的文章。对象界面并没有显示它的意图明显。

Roger clearly explained that property setters don't carry semantic information. Allowing a setter for a property like Post.PublishDate can add confusion as we can't know for sure if the post has been published or only if the publication date has been set. We can't know for sure that this is all that is needed to publish an article. The object "interface" does not show its "intent" clearly.

我相信,虽然,像已启用属性并携带足够的语义为得到和设置。这是一件应该立即生效,我不认为有必要SETACTIVE()或激活()/停用()单独的属性setter缺少语义的原因的方法。

I believe, though, that properties like "Enabled" do carry enough semantic for both "getting" and "setting". It is something that should be effective immediately and I can't see the need for SetActive() or Activate()/Deactivate() methods for the reason alone of missing semantics on the property setter.

不变量

罗杰还谈到通过属性setter打破不变的可能性。这绝对是正确的,应该作出这样的协同工作,提供组合不变的价值(如三角形的内角使用罗杰的例子)属性,只读属性,并创建一个方法来设置它们放在一起,可以验证在一个单一的步骤中的所有组合。

Roger also talked about the possibility of breaking invariants through property setters. This is absolutely right, and one should make properties that work in tandem to provide a "combined invariant value" (as the angles of triangle to use Roger's example) as read-only properties and create a method to set them all together, which can validate all the combinations in a single step.

物业为了初始化/设置相关性

这是类似于具有不变量的问题,因为它会导致问题,应该进行验证/一起改变性质。想象一下以下code:

This is similar to the problem with invariants as it causes problems with properties that should be validated/changed together. Imagine the following code:

    public class Period
    {
        DateTime start;
        public DateTime Start
        {
            get { return start; }
            set
            {
                if (value > end  && end != default(DateTime))
                    throw new Exception("Start can't be later than end!");
                start = value;
            }
        }

        DateTime end;
        public DateTime End
        {
            get { return end; }
            set
            {
                if (value < start && start != default(DateTime))
                    throw new Exception("End can't be earlier than start!");
                end = value;
            }
        }
    }

这是二传手的验证,导致访问顺序依赖一个天真的例子。下面code说明了这个问题:

This is a naive example of "setter" validation that causes access order dependencies. The following code illustrates this problem:

        public void CanChangeStartAndEndInAnyOrder()
        {
            Period period = new Period(DateTime.Now, DateTime.Now);
            period.Start = DateTime.Now.AddDays(1); //--> will throw exception here
            period.End = DateTime.Now.AddDays(2);
            // the following may throw an exception depending on the order the C# compiler 
            // assigns the properties. 
            period = new Period()
            {
                Start = DateTime.Now.AddDays(1),
                End = DateTime.Now.AddDays(2),
            };
            // The order is not guaranteed by C#, so either way may throw an exception
            period = new Period()
            {
                End = DateTime.Now.AddDays(2),
                Start = DateTime.Now.AddDays(1),
            };
        }

既然我们不能改变的开始日期过去的结束日起对象(除非它是一个空期间,随着这两个日期设置为默认(日期时间) - 是的,它不是一个伟大的设计,但你明白我的意思......),试图先设定开始日期会抛出异常。

Since we can't change the start date past the end date on a period object (unless it is an "empty" period, with both dates set to default(DateTime) - yes, it's not a great design, but you get what I mean...) trying to set the start date first will throw an exception.

它变得更加严重,当我们使用对象初始化。由于C#不保证任何分配顺序,我们不能做任何安全假设和code可能会或可能不会引发取决于编译器选择一个例外。 BAD!

It gets more serious when we use object initializers. Since C# don't guarantee any assignment order, we can't make any safe assumptions and the code may or may not throw an exception depending on the compiler choices. BAD!

这是最终与类的设计有问题。由于财产不能知道要更新这两个值,就不能关闭的确认,直到两个数值实际上改变。您应该让这两个属性为只读,并提供一个方法来设置都在同一时间(失去对象初始化的功能)或完全移除属性验证code(可能引入类似的IsValid另一个只读属性,或验证它需要时)。

This is ultimately a problem with the DESIGN of the classes. Since the property can't "know" that you are updating both values, it can't "turn off" the validation until both values are actually changed. You should either make both properties read-only and provide a method to set both at the same time (losing the feature of object initializers) or remove the validation code from the properties altogether (perhaps introducing another read-only property like IsValid, or validating it whenever needed).

ORM水化*

水化,在一个简单的观点,意味着获得了持续的数据回对象。对我来说,这实在是与添加的逻辑背后物业制定者面临的最大问题。

Hydration, in a simplistic view, means getting the persisted data back into objects. For me this is really the biggest problem with adding logic behind property setters.

许多/大多数的ORM映射持久值到属性。如果你有改变对象的状态(其他成员)的内部属性setter你最终会试图验证对一个不完整的对象,验证逻辑或逻辑(一个仍然被加载)。这是非常相似的对象初始化问题,因为你无法控制秩序的字段是水分。

Many/most ORMs map the persisted value into a property. If you have validation logic or logic that changes the object state (other members) inside property setters you'll end up trying to validate against an "incomplete" object (one still being loaded). This is very similar to the object initialization problem since you can't control the order the fields are "hydrated".

大多数奥姆斯允许你映射的持久性私人领域,而不是属性,这将允许对象进行保湿,但如果你的验证逻辑主要取决于内部的属性设置器,你可能要复制它在其他地方检查加载对象是有效或不是

Most ORMs allow you to map the persistence to private fields instead of properties, and this will allow the objects to be hydrated, but if your validation logic lies mostly inside property setters you may have to duplicate it elsewhere to check that a loaded object is valid or not.

由于许多ORM工具支持延迟加载(一个ORM的一个基本方面!)通过使用虚拟财产(或方法)映射到领域将进行ORM来映射成田延迟加载对象,它是不可能的。

Since many ORM tools support lazy loading (a fundamental aspect of an ORM!) through the use of virtual properties (or methods) mapping to fields will make it impossible for the ORM to lazy load objects mapped into fields.

结论

那么,到了最后,以避免code复制,让奥姆斯执行是最好的,他们可以,根据不同的字段设置的顺序prevent令人惊讶的例外,它是明智的,从移动逻辑走属性setter。

So, in the end, to avoid code duplication, allow ORMs to perform as best as they could, prevent surprising exceptions depending on the order the fields are set, it is wise to move logic away from property setters.

我还是搞清楚这个验证的逻辑应该是。我们在哪里验证对象的不变量方面?我们在哪里把更高级别的验证?我们使用的奥姆斯钩来执行验证(的OnSave,OnDelete,...)?等等,等等等等。但是,这不是这个答案的范围。

I'm still figuring out where this 'validation' logic should be. Where do we validate the invariants aspects of an object? Where do we put higher-level validations? Do we use hooks on the ORMs to perform validation (OnSave, OnDelete, ...)? Etc. Etc. Etc. But this is not the scope of this answer.

这篇关于领域驱动设计,领域对象,对二传手的态度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆