Является ли субъект домена нарушением принципа единой ответственности?


13

Единственная ответственность (причина изменения) организации должна заключаться в том, чтобы однозначно идентифицировать себя, иными словами, ее ответственность должна быть обнаруживаемой.

DDD книга Эрика Эвана, стр. 93:

основная ответственность Сущностей заключается в установлении преемственности, с тем чтобы поведение могло быть четким и предсказуемым. Они делают это лучше всего, если их держать запасными. Вместо того, чтобы фокусироваться на атрибутах или даже поведении, разделите определение объекта Entity до наиболее внутренних характеристик, особенно тех, которые его идентифицируют или обычно используются для его нахождения или сопоставления. Добавьте только поведение, которое необходимо для концепции и атрибутов, которые требуются для этого поведения.

Помимо этого, обратите внимание на удаление поведения и атрибутов в другие объекты, связанные с основной сущностью Entity. Помимо проблем идентификации, сущности стремятся выполнять свои обязанности, координируя операции объектов, которыми они владеют.

1.

... обрезать определение объекта ENTITY до самых внутренних характеристик, особенно тех, которые его идентифицируют или обычно используются для его нахождения или сопоставления. Добавьте только поведение, которое необходимо для концепции ...

Как только объекту присваивается уникальный идентификатор , его личность устанавливается, и поэтому я предполагаю, что такому объекту не нужно какое-либо поведение, чтобы поддерживать свою идентичность или помогать ему идентифицировать себя . Таким образом, я не понимаю , что такое поведение является автор со ссылкой на (помимо findи match операции ) с « поведением , что имеет существенное значение для концепции »?

2.

... обрезать определение объекта ENTITY до самых внутренних характеристик, особенно тех, которые его идентифицируют или обычно используются для его нахождения или сопоставления. ... Помимо этого, обратите внимание на удаление поведения и атрибутов в другие объекты, связанные с ядром ENTITY.

Таким образом, любое поведение, которое не помогает идентифицировать сущность, но мы все равно охарактеризовали бы это поведение как внутреннюю характеристику этой сущности (то есть лай присущ собакам, полет присущ самолетам, откладка яиц присущ птицам). .), должны ли быть помещены в другие объекты, связанные с этой сущностью (пример: мы должны поместить поведение лая в объект, связанный с сущностью собаки)?

3.

Помимо этого, посмотрите, чтобы удалить поведение и атрибуты в другие объекты, связанные с ядром ENTITY.

а) MyEntityделегирует обязанности A_respи B_respобъектам aи b, соответственно.

Хотя большинство A_respи B_respработа выполняется , aи bслучаи, клиенты по - прежнему служили A_respи B_respчерез MyEntity, что означает , что с точки зрения клиента две обязанности принадлежат MyEntity. Таким образом, разве это не означает, что MyEntityтакже имеет A_respи B_respобязанности и как таковое нарушает SRP ?

б) Даже если мы предположим, что A_respи B_respне принадлежим MyEntity, по- MyEntityпрежнему несет ответственность AB_respза координацию операций объектов aи b. Так что не MyEntityнарушает ли SRP, поскольку как минимум у него есть две обязанности - однозначно идентифицировать себя, а также AB_resp?

class MyEntity
{
    private A a = ...
    private B b = ...


    public A GetA()
    { ... }

    public B GetB()
    { ... }

    /* coordinates operations of objects a and b */
    public int AworkB()
    { ... }
}

/* A encapsulates a single responsibility resp_A*/
/* A is value object */
class A
{ ... }

/* B encapsulates a single responsibility resp_B*/
/* B is value object */
class B
{ ... }

ОБНОВИТЬ:

1.

Поведение в этом контексте относится к семантическому поведению. Например, свойство класса (т. Е. Атрибут объекта домена), которое используется для однозначной идентификации, имеет поведение. Пока это не представлено в коде напрямую. Ожидаемое поведение заключается в том, что для этого свойства не будет повторяющихся значений.

Таким образом, в коде нам практически никогда не потребуется реализовывать поведение (т. Е. Операцию), которое каким-то образом будет поддерживать идентичность объекта, поскольку, как вы объяснили, такое поведение существует только как концепция в модели предметной области (в форме атрибута ID объект), но когда мы переводим этот атрибут ID в код, часть его семантики теряется (т. е. часть, которая неявным образом обеспечивает уникальность значения идентификатора, теряется)?

2.

Кроме того, такое свойство, как Age, не имеет контекста вне Entity Entity, и, как таковое, не имеет смысла перемещаться в другой объект ... Однако эта информация может легко храниться в отдельном месте, в котором находится уникальный идентификатор, следовательно, запутанная ссылка на поведение. Возраст может быть лениво загруженным значением.

а) Если Ageсвойство загружено с отложенной загрузкой, то мы можем назвать его поведением, даже если семантически Ageэто просто атрибут?

3.

Вы могли бы легко иметь операции, специфичные для Адреса, такие как проверка того, что это действительный адрес. Вы можете не знать об этом во время разработки, но вся эта концепция состоит в том, чтобы разбивать объекты на их мельчайшие части.

Хотя я согласен, что мы потеряли бы контекст, перейдя Ageв другой объект, контекст не был бы потерян, если бы мы переместили DateOfBirthсвойство в другой объект, но мы обычно не перемещаем его.

Какова основная причина, по которой мы бы переместились Addressв другой объект, но нет DateOfBirth? Потому что DateOfBirthэто более присуще Personсущности или потому что есть меньше шансов, что где-то в будущем нам может понадобиться определить операции, специфичные для DateOfBirth?

4. Я должен сказать , что я до сих пор не знаю, MyEntityесть также A_respи B_respобязанности и почему MyEntityже то , AB_respне считается нарушением SRP

EULERFX

1)

Поведения, на которые ссылается автор, - это поведения, связанные с сущностью. Это поведения, которые изменяют состояние объекта

а) Если я вас правильно понимаю, вы говорите, что сущность должна содержать только те поведения, которые изменяют ее атрибуты (то есть ее состояние )?

б) А как насчет поведения, которое не обязательно изменяет состояние объекта , но все же рассматривается как внутренняя характеристика этого объекта (пример: лай будет внутренней характеристикой Dogобъекта, даже если он не изменяет его) Собачье состояние )? Должны ли мы включить эти поведения в объект или они должны быть перемещены в другие объекты?

2)

Что касается перемещения поведения к другим объектам, автор имеет в виду конкретно объекты значения.

Хотя моя цитата не включает его, но автор упоминает в том же абзаце, что в некоторых случаях поведениеатрибуты ) также будут перемещены в другие сущности (хотя я понимаю преимущества переноса поведения в ВО)

3) Если предположить MyEntity(см вопрос 3. в моей должности) не нарушает SRP, бы мы говорим , что ответственность в MyEntityэто помимо всего прочего , также состоящих из:

а. A_resp + B_resp + AB_resp ( AB_respкоординаты объектов aи b)

или

б. AB_resp + делегирование A_respи B_respобъектам ( aи b) связанным с MyEntity?

4) DDD книга Эрика Эвана, стр. 94:

CustomerID - это единственный идентификатор Клиента ENTITY (рисунок 5.5), но номер телефона и адрес часто используются для поиска или сопоставления Клиента. Имя не определяет личность человека, но оно часто используется как часть средств его определения.

В этом примере атрибуты телефона и адреса перенесены в Customer, но в реальном проекте этот выбор будет зависеть от того, как клиенты домена обычно сопоставляются или различаются. Например, если у клиента много контактных телефонных номеров для разных целей, тогда этот номер телефона не связан с идентификационной информацией и должен оставаться в контакте с отделом продаж.

а)

CustomerID - это единственный идентификатор Клиента ENTITY (рисунок 5.5), но номер телефона и адрес часто используются для поиска или сопоставления Клиента. Имя не определяет личность человека, но оно часто используется как часть средств его определения.

Quote состояния , что только атрибуты , связанные с идентичностью должны оставаться в сущности . Я предполагаю, что автор означает, что сущность должна содержать только те атрибуты , которые часто используются для поиска или сопоставления этой сущности , тогда как ВСЕ другие атрибуты должны быть перемещены?

б) Но как / куда следует перемещать другие атрибуты ? Например (здесь предполагается, что атрибут address не используется для поиска или сопоставления, Customer и поэтому мы хотим вывести атрибут адреса из Customer):

если вместо того, чтобы Customer.Address(типа string) мы создали свойство Customer.Addressтипа Address, мы перенесли бы атрибут адреса в связанный объект VO (который имеет тип Address) или мы бы сказали, что он Customerвсе еще содержит атрибут адреса ?

с)

В этом примере атрибуты телефона и адреса перенесены в Customer, но в реальном проекте этот выбор будет зависеть от того, как клиенты домена обычно сопоставляются или различаются. Например, если у клиента много контактных телефонных номеров для разных целей, тогда этот номер телефона не связан с идентификационной информацией и должен оставаться в контакте с отделом продаж.

Не автор в неправильном здесь, так как если мы предположим , каждый из многочисленных контактных телефонов , которые Customerимеют только принадлежу к этому частности Customer, то я бы сказал , что эти телефонные номера связаны с идентичностью так же , как тогда , когда Customerбыл только один номер телефона ?

5)

Причина, по которой автор предлагает сократить сущность, заключается в том, что при первоначальном создании сущности «Клиент» существует тенденция к заполнению ее любым атрибутом, который можно представить связанным с покупателем. Это ориентированный на данные подход, который игнорирует поведение, в конечном итоге приводящее к модели анемичной области.

По теме, но я думал , что анемия модели предметной области результатов от перемещения поведения из - за сущности , в то время как ваш пример заполнением в объект с большим количеством атрибутов , которые привели бы Customerиметь слишком много поведения (так как мы, вероятно , также включаем в Customerтех поведениях , которые изменить эти дополнительные атрибуты ) и, следовательно, в нарушение SRP?

Благодарность


2
Я очень рекомендую Роберт Мартинс, сериал о чистом коде видео, cleancoders.com. Он подробно рассказывает о том, как разные принципы могут вызывать проблемы или уравновешивать друг друга. в противном случае я думаю, что часть формулы для вашего примера будет рассматривать промежуток времени, в течение которого работает объект Person. если он в течение короткого промежутка времени, как Покупка, то платежный адрес, используемый для покупки, будет частью этого и неизменным. если это для учетной записи библиотеки, то адрес должен быть в состоянии изменить.
cartalot

2
Я думаю, что этот вопрос может нарушать SRP ...;)
IntelliData

Ответы:


6

Поведение в этом контексте относится к семантическому поведению. Например, свойство класса (т. Е. Атрибут объекта домена), которое используется для однозначной идентификации, имеет поведение. Пока это не представлено в коде напрямую. Ожидаемое поведение заключается в том, что для этого свойства не будет повторяющихся значений. Нечто, такое как Адрес, которое может иметь свою собственную идентичность, но не существует вне контекста сущности «Человек», все равно должно быть перемещено в его собственный объект. Таким образом, продвижение сущности в совокупный корень.

Кроме того, такое свойство, как Age, не имеет контекста вне сущности Person и, как таковое, не имеет смысла перемещаться в другой объект. Контекст будет потерян, и, следовательно, вы можете с уверенностью определить, что это значение, которое необходимо для сущности человека. В противном случае вы не можете найти значение. Однако эта информация может быть легко сохранена в отдельном месте, что уникальный идентификатор, отсюда и запутанная ссылка на поведение . Возраст может быть лениво загруженным значением.

Итак, чтобы ответить на ваш вопрос. Нет, это не нарушает принцип единой ответственности. Я просто заявляю, что у Человека должен быть только личный материал, а не что-то вроде Адреса, более сложное и связанное с человеком, должно существовать как его собственная сущность.

Вы могли бы легко иметь операции, специфичные для Адреса, такие как проверка того, что это действительный адрес. Вы можете не знать об этом во время разработки, но вся эта концепция состоит в том, чтобы разбить объекты на их мельчайшие части, чтобы что-то подобное было относительно простым, если это сделано после факта.

Обновление: 1) В большинстве случаев проверка личности выполняется после сохранения объекта в хранилище данных. Это означает, что код, представляющий проверку сущности, существует, но существует в другом месте. Обычно он существует с кодом, который отвечает за выдачу значения идентификатора. Вот почему я утверждаю, что уникальность не представлена непосредственно в коде для сущности.

2) Правильное утверждение было бы, что Ageэто атрибут, который имеет поведение. Вам нужно будет задокументировать тот факт, что Age загружен с отложенной загрузкой, чтобы разработчик, использующий это свойство, мог принять точное решение о том, как использовать это свойство.

3) DateOfBirthобычно это другой объект; Объект даты, который уже имеет предопределенные операции над ним. В некоторых языках для объекта date уже определена целая модель домена. Например, в c # вы можете указать часовой пояс, если дата UTC, добавить и вычесть даты, чтобы получить временной интервал. Так что ваше предположение о переезде DateOfBirthбыло бы правильным.

4) Если единственное, что MyEntityделает, это делегирование и согласование, то нет, это не нарушает ПСП. Его сингл ответственности делегировать и координировать и будет обозначаться как на фасаде рисунок


Не могли бы вы посмотреть на обновление, которое я сделал?
EdvRusj

Обновлено мой ответ
Чарльз Ламберт

4

Очень хороший вопрос SRP не следует воспринимать так буквально. Идентификация / поиск не является обязанностью организации в отношении SRP. Кто-то другой отвечает за присвоение ему идентификатора (а именно магазина) и за его поиск (а именно хранилища ).

Основная цель объекта состоит в представлении концепций, раскрытых моделью. Единственная разница между сущностью и объектом значения заключается в том, что сущность имеет значение за пределами своих неидентифицирующих атрибутов. Например, если человек меняет свое имя, он все тот же человек, просто с другим именем.


1

Как только объекту присваивается уникальный идентификатор, его личность устанавливается, и поэтому я предполагаю, что такому объекту не нужно какое-либо поведение, чтобы поддерживать свою идентичность или помогать ему идентифицировать себя. Таким образом, я не понимаю, на какое поведение автор ссылается (помимо операций поиска и сопоставления) на «поведение, существенное для концепции»?

Если идентичность установлена, тогда да, объекту больше ничего не нужно идентифицировать. Поведения, на которые ссылается автор, - это поведения, связанные с сущностью. Это поведения, которые изменяют состояние объекта. Например, Customerсущность может иметь MakePreferredповедение. Причина, по которой автор предлагает сократить сущность, заключается в том, что когда изначально создается Customerсущность, существует тенденция заполнять ее любым атрибутом, который можно представить связанным с клиентом. Это ориентированный на данные подход, который игнорирует поведение, в конечном итоге приводящее к модели анемичной области.

Что касается перемещения поведения к другим объектам, автор имеет в виду конкретно объекты значения. Причина, по которой стоит перенести поведение в виртуальные организации, заключается в том, что виртуальные сервисы, как правило, «меньше», чем объекты, и поэтому более сфокусированы. Более того, такие аспекты, как неизменность и закрытие операций, упрощают рассуждения о коде, а также делают его более твердым .

Вместе с ВО объект является своего рода якорем, который координирует различные ВО, которые реализуют его поведение.

Что касается SRP, ваша путаница не является необоснованной. Одной из проблем со стереотипным ООП-реализацией сущностей является соотношение идентичности и состояния. Действительно, с поведенческой точки зрения личность не имеет ничего общего с поведением. Другими словами, идентичность сущности не требуется ни для одного из ее поведений. Существуют реализации, где устраняется эта путаница, например, AggregateSource или функциональный подход, который я описываю здесь .

Другая проблема заключается в том, что в некоторой степени SRP может быть качественной мерой. Любой может придумать определение единственной ответственности, которую нарушает какой-то класс. Можно сказать, что ответственность субъекта заключается в реализации поведения, требуемого от этого субъекта. В этом смысле он несет единственную ответственность. Кроме того, когда объект делегирует поведение составляющим ВО, это не нарушает SRP. SRP не запрещает состав такого рода. Он предостерегает от необходимости сводить связь между объектами до абсолютного минимума, поддерживать интерфейс как можно более чистым и т. Д.

ОБНОВИТЬ

а) Если я вас правильно понимаю, вы говорите, что сущность должна содержать только те поведения, которые изменяют ее атрибуты (то есть ее состояние)?

Да, хотя есть исключения ...

б) А как насчет поведения, которое не обязательно изменяет состояние сущности, но все же рассматривается как внутренняя характеристика этой сущности (пример: лай будет неотъемлемой характеристикой сущности собаки, даже если это не так изменить состояние собаки)? Должны ли мы включить эти поведения в объект или они должны быть перемещены в другие объекты?

Для сущностей допустимо содержать фабричные методы для создания экземпляров сущностей, которые фактически являются дочерними сущностями, но там, где ссылки на объекты не используются для обхода. В этом случае дочерняя сущность должна сохраняться службой приложений. Служба приложений использует родительский объект для создания дочернего объекта.

3) Предполагая, что MyEntity (см. Вопрос 3. в моем исходном сообщении) не нарушает SRP, мы бы сказали, что ответственность MyEntity, помимо прочего, состоит из:

Вы смотрите на ответственность с точки зрения реализации. Вместо этого рассмотрите сущность как своего рода черный ящик с обязанностями. То, как он справляется с этим, не представляет интереса для вас, как человека, смотрящего со стороны. Распределение обязанностей между ВО или даже другими организациями является проблемой реализации.

В кавычке говорится, что в сущности должны оставаться только атрибуты, связанные с идентичностью. Я предполагаю, что автор означает, что сущность должна содержать только те атрибуты, которые часто используются для поиска или сопоставления этой сущности, тогда как ВСЕ другие атрибуты должны быть перемещены?

Более конкретно, атрибуты, которые не требуются ни для поведения, ни для поиска, не должны быть частью сущности. Зачем беспокоиться? Более того, с чем-то вроде шаблона чтения-модели , сущностям не нужно ничего, кроме атрибутов, необходимых для поведения.

если вместо Customer.Address (типа string) мы создадим свойство Customer.Address типа Address, переместим ли мы атрибут address в связанный объект VO (который имеет тип Address) или мы бы сказали, что Customer по-прежнему содержит address атрибут?

Да, по сути, нет разницы между строковым адресом или адресом VO-адреса.

Не ошибается ли автор здесь, так как, если мы предположим, что каждый из множества контактных телефонов, которые есть у Клиента, принадлежат только этому конкретному клиенту, то я бы сказал, что эти номера телефонов связаны с идентичностью так же, как если бы только один номер телефона?

Я не на 100% намерен автором, но я думаю, что он просто описывает, как требования к поиску сущностей могут изменить то, как сущность и ее соответствующие виртуальные организации являются структурами.

Не по теме, но я подумал, что анемичная модель предметной области является результатом перемещения поведения из сущности, в то время как в вашем примере это заполнение сущности множеством атрибутов, что приведет к тому, что Customer будет иметь слишком большое поведение (поскольку мы, вероятно, также включили бы в Customer поведения, которые изменяют эти дополнительные атрибуты) и, следовательно, в нарушение SRP?

Много атрибутов не подразумевает много поведения. На самом деле это обычно говорит об обратном. Много атрибутов с геттерами и сеттерами, но без инкапсулирующего поведения.


Я сделал обновление
EdvRusj

1

TL; DR: ты слишком обдумал это. Тем не менее, мне было весело думать об этом вместе с вами. Так пристегнуться ....

Единственная ответственность (причина изменения) организации должна заключаться в том, чтобы однозначно идентифицировать себя, иными словами, ее ответственность должна быть обнаруживаемой.

Нет, это не правильно. Единственная ответственность организации - преемственность.

Идентичность является новым следствием преемственности. Моделирование идентичности как отдельной идеи - это оптимизация производительности.

Вот пример: патрон ресторана дает машину камердинеру. Через час патрон ресторана просит машину. Должен ли камердинер дать это?

Легко сказать, что камердинер должен отдать машину, если покровитель «тот же». Но что это на самом деле означает? Правильный способ определить это - начать с «теперь» патрона и поискать в истории этого патрона задом наперед, чтобы увидеть, является ли передача автомобиля камердинеру частью этой истории.

Конечно, мы не можем этого сделать. У нас есть проблемы с отслеживанием нашей собственной истории точно, не говоря уже об истории чего-то, что не было с нами все время. Таким образом, вместо использования истории покровителя, мы берем короткие пути. Есть ли у патрона заглушка билета с тем же номером, что и у тега, привязанного в настоящее время к ключам? Соответствует ли водительское удостоверение в кошельке патрона имени, указанному в названии на DMV, изображение на водительских правах напоминает лицо патрона. И т.п.

Вкратце: вместо проверки истории посетителя мы проверяем текущее состояние посетителя, чтобы увидеть, соответствует ли текущее состояние истории, которая охватывает период между прибытием автомобиля и запросом на его возврат.

При моделировании сущностей мы используем аналогичную оптимизацию. Мы даем всем организациям общую ответственность

  1. Обеспечение того, чтобы начало истории включало присвоение неизменяемого идентификатора состоянию объекта
  2. Обеспечение того, чтобы следующее состояние всегда включало точную копию идентификатора предыдущего состояния.

Я не описываю здесь вторую ответственность организации; Сущность по-прежнему отвечает за преемственность - следит за тем, чтобы история была последовательным повествованием. Обязанности идентификатора - это просто подмножество, общее для всех объектов.

У нас пока нет принудительного применения уникальности. Это невозможно в пределах одной сущности, потому что уникальность требует доступа к состоянию всех сущностей; где один объект имеет доступ только к своему.

Еще раз, проверка всех идентификаторов каждый раз не практична, поэтому вместо этого мы удовлетворяем уникальность простым способом: код, который генерирует следующий идентификатор, никогда не должен повторяться.

В конце концов, это означает, что мы можем проверить непрерывность, протестировав эквивалентность двух разных частей состояния в памяти, сэкономив много времени при попытке запроса ациклических графов.

Вы также, кажется, перепутали Принцип Единой Ответственности (который является действительно хорошей идеей) с принципом атомарной ответственности. Разложение ответственности на более мелкие, более легко управляемые части совместимо с SRP.


-3

Ну, это зависит от того, как вы хотите посмотреть на это.

Другой способ: «Является ли принцип единой ответственности нарушением сущности домена?»

Оба являются руководящими принципами. В разработке программного обеспечения нет «принципа». Однако есть хорошие дизайны и плохие дизайны. Обе эти концепции могут быть использованы по-разному, чтобы добиться хорошего дизайна.


Необъяснимые понижения == Фанаты SRP
Боб
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.