Атрибуты доступа к сервису - PullRequest
1 голос
/ 28 апреля 2019

В oop мы стремимся к инкапсуляции .Мы стараемся не раскрывать внутреннее состояние через геттеры или открытые поля, только выставляем методы.

Пока все хорошо.

В ситуации, когда мы хотим работать с несколькими сущностями , мы вводим Сервис .Но как этот сервис может свободно работать на этих объектах?

Если все (и Service, и Entities) были в одном пакете, Entities могли бы предоставлять закрытые методы или поля пакета, и Service мог бы использовать их, сохраняя инкапсуляцию.Но что, когда сущности и сервисы из разных пакетов?Кажется, что сущности должны либо выставлять открытые методы получения (первый шаг к анемичной модели и утратить логику у сущностей), либо публичные методы, выполняющие логику, специфичную для потребностей службы, возможно, вводимую только требованиями этой службы, также кажутся плохими.Как с этим справиться?

Ответы [ 3 ]

1 голос
/ 28 апреля 2019

В контексте ОО, наиболее важная вещь для вас, чтобы понять, что объекты отвечают на сообщения , и что в ОО P в частности, методы какэти ответы реализованы .

Например, представьте, что у вас есть объект Person, на который вы (как программист) возложили ответственность за ответ на сообщение «grow».Как правило, вы реализуете это как Person.grow() метод, подобный этому.

class Person {
    int age;

    public void grow() { this.age++; }
}

Это кажется довольно очевидным, но вы должны заметить, что с точки зрения отправителя сообщения, как реагирует объект Person, не имеет смысла.Несмотря на все это, метод Person.grow() мог бы запускать запуск ракеты, и это не имело бы значения, потому что какой-то другой объект (или объекты) мог бы реагировать правильно (например, компонент пользовательского интерфейса обновляется на экране),Однако вы решили, что когда объект Person обрабатывает сообщение «grow», он должен увеличивать значение своего атрибута age.Это инкапсуляция.

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

Наконец, вы можете задавать себе вопрос: как субъекты узнают, что им нужно отвечать на определенные сообщения? На это легко ответить: ВЫ решаете, как связать сообщения с ответами.Другими словами, вы думаете о требованиях вашего приложения (какие «сообщения» будут отправляться различными объектами) и как они будут удовлетворяться (как и какие объекты будут отвечать на сообщения).

0 голосов
/ 01 мая 2019

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

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

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

Это то, что касается методов set , а как насчет get ?
Поскольку методы набора могут рассматриваться как «команда» агрегата, вы можетевоспринимайте геттеры как методы «запроса», используемые для запроса данных к агрегату.Запрашивать данные для агрегата вполне нормально, если это не нарушает ответственность агрегата за соблюдение инвариантов.Это означает, что вы должны следить за тем, что возвращает метод запроса.
Если результатом метода запроса является значение объект, то есть неизменяемый, вполне нормально иметь его.Таким образом, кто запрашивает агрегат, он возвращает что-то, что может быть только прочитано.
Таким образом, у вас могут быть методы запроса, выполняющие вычисления с использованием внутреннего состояния объекта (например, метод int missingStudents(), который вычисляет количество пропавших учеников дляLesson сущность, которая имеет totalNumber студентов и List<StudentId> во внутреннем состоянии), или простые методы, такие как List<StudentId> presentStudent(), которые просто возвращают список во внутреннем состоянии, но что отличается от List<StudentId> getStudents() его простоимя).
Таким образом, если метод get возвращает что-то неизменное, использующее его, не может нарушить инварианты агрегата.
Если метод возвращает изменяемый объект, который является частью агрегатного состояния, любой, кто имеет доступобъект может запрашивать этот объект и теперь может изменять что-то, что остается внутри агрегата, не пропуская правильные методы команд, пропуская проверку инвариантов (если это не то, что нужно и управляется).
Другая возможность состоит в том, что объект создается намуха во время запроса и не является частью агрегатаУкажите, поэтому, если кто-то получит к нему доступ, а также, если он будет изменчивым, агрегат будет безопасным.В конце концов, методы get и set кажутся уродливыми, если вы экстремист DDD, но иногда они также могут быть полезны, будучи стандартным соглашением об именах, и некоторые библиотеки работают над этим соглашением об именах, поэтому я не вижу их плохими, если они не нарушают совокупные / юридические обязанности.

И, наконец, когда вы говорите В ситуации, когда мы хотим работать с несколькими сущностями, мы вводим Сервис. , это правда, но сервис также должен работать (изменять, сохранять)на одном агрегате, но это уже другая тема ?.

0 голосов
/ 30 апреля 2019

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

Нет, мы не делаем. Ну, я думаю, что некоторые люди делают, но дело в том, что они не должны .

В объектно-ориентированной модели мы моделируем конкретную проблемную область. Мы (опять же, не должны) различать, основываясь на том, какое количество других объектов работает с одним объектом. Если мне нужно смоделировать Appointment и коллекцию Appointment, я не введу AppointmentService, я введу Schedule или Timetable, или что-либо еще подходящее для домена.

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

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

Так что или OOP или делать DDD, вы не можете сделать оба. Здесь - мой разговор (разговор на немецком языке, но слайды на английском) о OO и DDD.

...