Избегайте геттеров и сеттеров, отображающих информацию о пользователях

10

Фон

Я читаю «Чистую книгу кодов», и, в частности, я работаю над художественными объектами Kata, как банковский счет, и я застрял на этом правиле:

Девятое правило художественных объектов - мы не используем геттеры или сеттеры.

Это кажется довольно забавным, и я согласен с этим принципом. Более того, на странице 98-99 Чистого кода автор объясняет, что геттеры / сеттеры нарушают абстракцию и что нам не нужно спрашивать наш объект, но мы должны сказать наш объект.

Это имеет смысл в моем сознании, и я полностью согласен с этим принципом. Проблема приходит на практике.

контекст

Например, у меня есть приложение, в котором я должен перечислить некоторых пользователей и отобразить данные о них.

Мой пользователь состоит из:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

проблема

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

Что приходит мне в голову

Одним из решений является сделать:

user.getName().getFirstName().getStringValue()

Что ужасно, нарушая многие правила художественных объектов и нарушая Закон Деметры.

Еще один будет что-то вроде:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

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

Есть идеи ?

mfrachet
источник

Ответы:

17

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

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

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

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

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

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

Энди
источник
Хорошо, я думаю об этом предложении, как о сопоставлении между моей сущностью домена, с пользовательским DTO для моего уровня представления, который будет иметь некоторые права доступа?
mfrachet
@ Маргин В значительной степени, да.
Энди
Все это каскадное звучание звучит очень хорошо и гладко, спасибо за ответ;)
mfrachet
2

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

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

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

String accountName = user.formatDescription("$(firstname).$(lastname)");

Вы также можете определить некоторые часто используемые, возможно, сложные форматы один раз, так что вы можете сказать, например,

String fullAddress = user.formatDescription(User.kAddressFormat);

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

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

cmaster - восстановить монику
источник
5
Это, однако, выглядит как нарушение SRP для меня. На самом ли деле ответственность за Userсинтаксический анализ и компиляцию / интерпретацию языка шаблонов лежит на объекте?
Йорг Миттаг
@ JörgWMittag Не обязательно. Как я уже сказал, принцип KISS имеет приоритет. И я нигде не сказал, что Userкласс должен сам реализовать эту функциональность. Если бы у меня было только два класса, которые нуждались в такой функциональности, вы могли бы поспорить на то, что я выделю механизм замены шаблона в свой собственный класс. Это должно быть примером того, как вы можете поднять абстракцию, Userобеспечивающую уровень, на котором она фактически больше, чем просто контейнер данных. И я верю, что это то, что нужно избегать аксессоров: делать ООП вместо обработки множества structs.
cmaster - восстановить
Вы знаете, что KISS является полностью субъективным и объективным SRP? KISS ничего не говорит вам о том, что делать. И то, что «просто» для вас, может не быть «простым» для меня. Я вижу реальную разницу в качестве, если спорю с KISS или SRP.
oopexpert