×Закрыть

Інкапсуляція в Java

Мене давно непокоїть одна річ. В комерційних проектах, в опенсорсі, в туторіалах ми всі спостерігаємо одне й те саме:

public class User {

    private String id;

    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
Всі називають це «інкапсуляцією». Але чим це відрізняється від
public class User {

    public String id;

    public String name;

}
?

В чому зміст такої «інкапсуляції»? Що ми таким чином «інкапсулюємо»? Чому ця штука тягнеться роками? Діскасс.

LinkedIn

Лучшие комментарии пропустить

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

ООД? Не, не слышали. Абстракция, слабая связность? Да нафиг. Инверсия зависимостей? Ашоэта?

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

Теперь на собесах еще и про отношение к прямому доступу к полям можно спрашивать. «геттер бойлерплейт кококо прямой доступ кококо» == двери там.

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

Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Разнообразие предположений — удивило. Смотрим Wikipedia на тему инкапсуляции. Она определяет инкапсуляцию как ограничение доступа к данным компонента (в альтернативе примере автора нет ограничений) или обьединение данных с методами обработки (в альтернативе примере автора нет ограничений). Из-за чего спор?

Можно lombok добавить или kotlin data классы использовать.

Хмм, какая свежая идея. Почему никто из ниже комментирующих еще не предложил..

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

А так бы создавали копию предыдущей ДТОшки с разницей в одно поле

Так як це роблять всі інші:

new DTO(oldDTO, changedField)
or
new DTO(oldDTO.id, ..., changedField, oldDTO.x);
or
builderPattern;

Є різні кейси. Для різних кейсів — різний підхід. Не треба натягувати одни і той же підхід на всі проблеми.
Якщо поле може бути змінено тільки одне — можна додати додатковий конструктор що копією всередині DTO + 1 field. Так буде швидко і зручно. (Нагадую, що задача любого ПО — це рішення задач бізнесу. А бізнесу треба швидко, дешево і якісно).
Якщо багато полів може бути змінено — білдер чи через конструтор руцями.

User setUserName = new User(oldUser, name);
User setUserAge = new User(setUserName , age);
User setUserRole = new User(setUserAge , userRole);
return setUserRole;

Ні, так ніхто якраз не робить. До вашого коменту я навіть не думав, що так можна =). Відчуваю віяння зі сходу.

в том коде была проблема не только в сеттерах, естественно. но наличие сеттеров развращает рукоблудных — и в последствии дает возможность сделать из небольшой порции вермишели большую каструлю :D

но наличие сеттеров развращает рукоблудных — и в последствии дает возможность сделать из небольшой порции вермишели большую каструлю :D

Ніт.
Человек, который тяент и мутирует ДТО (даже если предположить что вы тут подразумиваете аналог си структуры), наг...ет в любом случае. Как вам уже написали выше ничто не помешает ему пробрасывать копии с измененным 1 полем, так «кастрюля» даже больше получится.
Если у человека есть голова на плечах, то он не будет вызывать сеттеры там где не надо или скорее всего сделает из ДТОшки объекты для подходящего слоя.

увы, но от совсем диких ничего не спасет

Действительно, зачем создавать один обьект, там где можно создать тысячу..

Почитайте «Effective Java» Дж. Блоха, этот и многие другие вопросы отпадут

Блох до сих пор рекомендует пользоваться checked exceptions, в то время как весь мир ушёл от этого еще лет 8 назад.

1) как это вяжется с инкапсуляцией? или одно утверждение делает невалидным всю книгу? В Хортсмане 5ти летней давности испольуют анонимные классы, вместо лямб, это делает всю книгу не актуальной?
2) Вы имеете ввиду «use checked exceptions for conditions from which the caller
can reasonably be expected to recover» ? Ох уж этот Блох, проклятый старовер.
3) Читая книгу (особенно старого издания) всегда нужно матчить информацию с акутальной на данный момент, но некоторые вещи остаются неизменными(особенно если мы говорим о парадигмах программирования, коей является инкапсуляция)

как это вяжется с инкапсуляцией? или одно утверждение делает невалидным всю книгу? В Хортсмане 5ти летней давности испольуют анонимные классы, вместо лямб, это делает всю книгу не актуальной?

Это говорит о том, что не стоит принимать всё за чистую монету. Сам Блох говорит:

However, if a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields—assuming they do an adequate job of describing the abstraction provided by the class. This approach generates less visual clutter than the accessor-method approach, both in the class definition and in the client code that uses it. While the client code is tied to the class’s internal representation, this code is confined to the package containing the
class. If a change in representation becomes desirable, you can make the change without touching any code outside the package.

Т.е. он говорит, что для классов, которые мы можем легко изменить, вполне отлично не использовать акцессоры. Учитывая, что 99% кода, который мы пишем — это внутренний код, который нет никакой проблемы изменить, я не вижу причины не распространять данное утверждение до уровня приложения или модуля.

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

Абсолютно верно (кроме утверждения, что инкапсуляция — это парадигма программирования). Инкапсуляция является средством снижения связности кода. Я утверждаю, что акцессоры в том виде, в котором они представлены в начале поста (как средство «контроля доступа» к полям в value object), снижают связность кода минимальным образом, поскольку они не снижают кратности связей (т.е. если ваш класс А сейчас зависит от 6 акцессоров класса Б, заменив их полями, вы ни уменьшите, ни увеличите кратность этой связи). Поэтому целесообразность акцессоров как минимум спорна. And discuss.

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

Можно спросить, а с чем вы тогда спорите?

Я понял, что под следующим:

Почитайте «Effective Java» Дж. Блоха, этот и многие другие вопросы отпадут

Вы говорили как раз об «Item 16: In public classes, use accessor methods, not public fields», который, не смотря на мою цитату из книги, всё ещё безапеляционно говорит «для публичных классов всегда создавайте акцессоры».

нет, я иммел ввиду что для DTO, Value objects и подобных мы можем использовать доступ через паблик поля, для public API — использовать accessor methods для возмонжости расширения без изменения самого контракта

if a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields—assuming they do an adequate job of describing the abstraction provided by the class.

Да, это правда.

Только это правда при 1 условии, а именно, что мы рассматриваем сфероконя в вакууме.

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

А предотвращение этой проблемы очень простое — изначально пилить все на гет/сет, исключив возможность возникновения проблемы.

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

И что происходило? Каким именно образом это делало код неподдерживаемым? И чтобы не было разночтений ещё раз повторю, что я говорю именно о value object типа того, который представлен вверху.

А предотвращение этой проблемы очень простое — изначально пилить все на гет/сет, исключив возможность возникновения проблемы.

В моей практике отсутствие акцессоров ни разу не было причиной неподдерживаемости базы кода, а их добавление — ни разу не было решением.

Миллион раз так делал.

Я теж. Напротязі останніх 4 років над одним і тим же проектом. Жодних проблем.
Більше того, наші конкуренти успішно беруть наш код модифікують і розширюють під свої потреби і перепродають. Пробем у них я теж не помітив.

Кстати в эту тему, вчера ковырялся в гугловой офф PHP либе для доступа к их апишкам. Ребята те ещё тролли:
github.com/...​yticsReporting/Metric.php

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

так как дто по факту структура данных
In other words, DTOs are simple objects that should not contain any business logic but may contain serialization and deserialization mechanisms for transferring data over the wire

Вот вы и продемонстрировали проблему с «дата классами» — разработсики возвращаются к структурам, называя их ДТО или ВалуеОбжект, и к процедурному стилю, называямодули с процедурами сервисами.

Один из примеров когда для ДТО полезны аксессоры — данные хранятся не в полях, а в массиве, строке или каком-то байт-буффере.

Вот вы и продемонстрировали проблему с «дата классами» — разработсики возвращаются к структурам, называя их ДТО или ВалуеОбжект, и к процедурному стилю, называямодули с процедурами сервисами.

контролер отримує дані — робить з них дто — передає в сервіс де процідурки вже працюють з дто-шчками роблячи виклики в інші сервіси.

Так написано 80% кода і вони називають це ООП.

в цьому ООП ще питання хто кому об’єкт :)

разработсики возвращаются к структурам, называя их ДТО или ВалуеОбжект, и к процедурному стилю, называямодули с процедурами сервисами.

я вообще считаю что идти на 100% в 1 парадигму — нецелесообразно.

Один из примеров когда для ДТО полезны аксессоры — данные хранятся не в полях, а в массиве, строке или каком-то байт-буффере.

обычно это делается кастомными маперами

разработсики возвращаются к структурам, называя их ДТО или ВалуеОбжект, и к процедурному стилю, называямодули с процедурами сервисами.

Они не возвращаются, они никуда оттуда и не уходили. 90% проектов — это по сути процедурные программы, состоящие из «сервисов» (bags of methods) и дто чуть более чем на 100%. Потому что реальный ООП — это сложно, голова типа начинает болеть. А так — наляпал геттеров с сеттерами, и типа инкапсуляция готова, и ООД типа.

Ценность понятия value object и его обособления в том, что они чётко разграничивают структуры данных (в которых геттеры не несут никакой реальной пользы в контексте инкапсуляции) и реальные объекты (в которых геттеры должны активно удаляться по принципу «tell don’t ask»). Всё по Эвансу.

То мабуть є на те свої підстави. Бізнес-процеси, вони ж «процеси», не дарма співзвучні зі словом «процедура».

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

А для людей религиозных придумали loombok.

це все через відсутність в Джява можливості визначити власний велью тип

Ага, и потом джуны 100500 ошибок допускают из-за непонимания де оно копируеться по ссылке а де по значению. Уж лучче без.

ви цей, головне джунам ключі од гарбадж колєктора не давайте ;)

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

ООД? Не, не слышали. Абстракция, слабая связность? Да нафиг. Инверсия зависимостей? Ашоэта?

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

Теперь на собесах еще и про отношение к прямому доступу к полям можно спрашивать. «геттер бойлерплейт кококо прямой доступ кококо» == двери там.

Это все потому что в джаву проперти не завезли

Это все потому что в джаву проперти не завезли

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

Не пришей кобыле ломбок

Мені здалось, що питання переважно було про класи -дто, які по суті аргументи функцій різних далів, репозиторіїв, сервісів, і т.п., написаних в процедурному стилі. І от, ООД, воно для них ? Вони самі по собі не «інтерфейс» ? Якщо вся їхня задача перетворитись в json і піти в веб ? Повірте, тут не все так однозначно, і ви ж можете до автора теми на співбесіду прийти ;)

Это всё прекрасно. Пока оно не оказывается в боевом коде насобачено в каждую дырку.

Правильно — это если естественно сущности связаны сильно, или не связаны вовсе (композиция), не собачить туда никакой дополнительной логики вообще. Инициализироваться оно должно ровно там, где создаётся. В том же [падшая женщина] участке кода, не вынуждая читать 100500 RTFMов, в особенности когда их нихера не написано вообще.

Почему так: в случае сильных связей, ты понимаешь логику цельным куском, и когда пишешь, и когда читаешь. В случае композиции — сама композиция является этой самой сильной связью, и ты понимаешь ГДЕ и КОГДА происходит связывание.

Самое долбанутое — это собачить гетеры и сетеры тупо в классы данных, которые другой самостоятельной логики не имеют, и которую должен знать тот кто её применяет. Почему так: когда ты встречаешь в коде присваивание — ты видишь, что ничего другого не произойдёт, и произойти не может. Когда встречаешь setЧеготоТам — ты ждёшь что произойдёт полноценный set, с проверками допустимости, если таковые есть в классе, с поправкой соответствующих зависимостей. А если этого всего нет — то ЖОПА случается, ибо ты можешь заметить баг когда он есть — а когда баг в том, что куска кода просто нет (а выглядит будто есть) — то баг не виден ни в файле класса, ни в коде его использования.

Можно ли протестить код, которого нет? Разумеется, нет. Потому что знал бы где упасть — соломки б подстелил.

С чем встречался я: Класс, задающий геометрические размеры, и соответственно в нём же единицы измерения (выбор из ENUM). Какой-то мудрец решил, что установка другой единицы измерения НЕ ДОЛЖНА пересчитывать константы, равно как и НЕ НУЖНО менять данные, выдаваемые по get — типа ТыжПрограммист должен был сам всё это пересчитать, а поле единицы измерения задавало только соответствующее поле, и всё. Было бы там присваивание — ясно-понятно, никто бы не ждал пересчёта. А через гет-сет, потом и вылезало это дерьмище в боевом коде — на печати в бланки строгой отчётности, которые с водяными знаками и т.п.

С чем встречался я: Класс, задающий геометрические размеры, и соответственно в нём же единицы измерения (выбор из ENUM). Какой-то мудрец решил, что установка другой единицы измерения НЕ ДОЛЖНА пересчитывать константы, равно как и НЕ НУЖНО менять данные, выдаваемые по get — типа ТыжПрограммист должен был сам всё это пересчитать, а поле единицы измерения задавало только соответствующее поле, и всё.

Видел код, где сеттеры триггерили ивенты что что-там изменилось, а в ивент-хендлерах — «присваивание» (C#) к другим сеттерам, в которых тоже триггерились ивенты, и так далее :)

Если константы надо «пересчитывать», то вавка в голове дошла до таких размеров, что работоспособность программы уходит на второй, а то и на третий план

Секрет Полишинеля: констант не существует. То что какие-то данные запроектированы как условно константы — знает только архитектор класса, похоронив эти знания в своём setSomething()

Считать, что человек, использующий класс, обязан перечитать его исходный код — вот где вавка!

Никаких условных констант не бывает, бывают константы и бывают переменные, если кто-то разницы не понимает, то надо его сдать в поликлинику для опытов

Красава. Всі положняки розказав 👍

Теперь на собесах еще и про отношение к прямому доступу к полям можно спрашивать. «геттер бойлерплейт кококо прямой доступ кококо» == двери там.

действительно и в обратную сторону

действительно и в обратную сторону

Да похер.
Если интервьюер мне на собесе задвинет тему про кококо только паблик филды кококо а нам норм я сам встану и уйду.

кококо

YAGNI & рефакторинг? Видимо, не слышал.

Теперь на собесах еще и про отношение к прямому доступу к полям можно спрашивать. «геттер бойлерплейт кококо прямой доступ кококо» == двери там.

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

из армированного бетона.

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

не вляпаться

Не волнуйся, не вляпаешься, таких не возьмем.

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

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

твой хрустальный шар еще и позволяет видеть код на расстоянии

Мне не надо видеть твой код. Твоих постов предостаточно, чтобы не хотеть его видеть.

в своем узколобом мирке

Азаза

Иди полирни хрустальный шар.

Люблю наблюдать как джависты обсуждают недо-язык php с великим пафосом, а тут прям оказывается им стоит на своих же коллег обратить внимание.

Люблю наблюдать как джависты обсуждают
Javascript developer

Наблюдай, мне не жалко :)

Ваш ответ ведь не зависит от содержимого поля «должность» в профиле ДОУ ?

Не поверите, но и в других языках/платформах (JS/TS в частности) такая же проблема.

По Блоху:

> You can’t change the representation without changing the API, you can’t enforce invariants, and you can’t take auxiliary action when a field is accessed.
> If a public class exposes its data fields, all hope of changing its representation is lost because client code can be distributed far and wide.
> However, if a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields—assuming they do an adequate job of describing the abstraction provided by the class.

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

Весе это было актуально во времена до «победы опенсурса и вершн контроля».

А що, в джаву досі проперті не завезли?

Сетами ховаєш внутрішню кухню — наприклад передаєш щось в правильному чи не правильному форматі, то сетер порішає (не сам, звісно, потрібно передбачити). А гетом зручно діставати щось, бо об`єктів овер купа і в них овер купа полів, деколи можеш не знати що і як називається там, тому пишеш .get і все зайве пропадає — IDE дасть підказку тільки по полях, бо інакше буш грати в бінго.

наприклад передаєш щось в правильному чи не правильному форматі, то сетер порішає

Ви бачили таке в реальних проектах? В класах типу якого я написав?

Насправді зовсім не часто, але таке деколи бачив. Я думаю, що це просто будують по принципу best practice — щось на кшталт «а вдруг стане в нагоді».

например сеттер делающий копию параметра вместо простого присваивания — сплошь и рядом

Такая «инкапсуляция» ни к селу ни к городу. В скале например, сделали специальный тип классов — данных case class, которые по своему предназначению являются контейнерами для немутирующих переменных, и по сути есть гетерогенные списки с именованными полями. case class Foo(id: Id, name: Sting) вот вам и весь класс который нарисован в посте. Они вообще довольно замечательная штука — для них есть механизмы автоматического вывода кодеков во все нужные форматы, их же можно между разными моделями гонять при помощи shapeless, их можно засовывать в паттерн матч. Да и прививают они хороший стиль — не завязывать данные на логику а логику на данные.

Да и прививают они хороший стиль — не завязывать данные на логику а логику на данные.
хороший стиль

топ кек

Именно про это АОП и Тайп-классы — чтобы не делать километровые классы с сотнями методов, которые имплементируют десятки интефейсов. Если класс ничего не будет знать про интерфейс, и иплиментировать его будет другая сущность то от этого сам класс стане только меньше размером и проще для понимания, а кроме того — связь одного с другим порвётся. Один только вин.

Ви бачили таке в реальних проектах? В класах типу якого я написав?

Видели. Потом кошмарами мучались.

Ви бачили таке в реальних проектах? В класах типу якого я написав?

Чого в тих гетерах та сетерах буває тільки не побачиш.

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

Дата — это образный пример, если шо

Вот почему сам класс должен отвечать за то как его собрать из другого формата? Этим должен заниматься кодек.

Согласен с Иваном — пример не очень. Получается внедрение в класс знаний о внешних форматах.

Если на одну и туже дату вешаеться еще и джексон, жпа, или еще что — то все это превращаеться в такой гемор, что проще «задолбаться» кодеками, фектори, и прочим.

1. Паблик поля єто не инкапсуляция.
2. Ломбок

Что бы потом можно было написать в тестах
Mockito.when(user.getId()).thenReturn(null)

топ кек. зробити new User(id, name) швидше буде.

то скарказм был, я так понимаю

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

доступа к контексту графической оболочки
java

pick one

Если у вас за

user.getId()

скрываются

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

, то у вас крупные проблемы.

В чому зміст такої «інкапсуляції»? Що ми таким чином «інкапсулюємо»? Чому ця штука тягнеться роками? Діскасс.

очень много дурацких вещей тянутся годами. посмотрите на итоги выборов, например (КВН vs Ein Volk, ein Führer).

пишите на Scala и не насилуйте себе мозг

Scala

про це гамно я окремо пізніше напишу.

enjoy your функтор

про це гамно я окремо

окремим топiком, плз

Ждем-с, ты только на форум пиши, нормально по пацански перетрем, а то в ленете тоталитарный режим. :-)

ленете

ват?)

Ймовірно, мається на увазі те, що якщо опублікувати пост не на форумі, а тут
dou.ua/lenta
то коментування буде доступне тільки підтвердженим аккаунтам і недоступне анонімним аккаунтам.

Нічосі я й не знав. Свободу попугаям!

О, привет, дорогой неосилятор. Котики с шейплсами вас напугали? Или смена майндсета?

А ты когда успел осилить? На продлёнке?

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

Скальная архитектура, инфраструктура, стек, деплой — паттерны радикально отличается от джавных, и слепое следование as Better Java ни к чему хорошему не приведёт. Нужно делать всё Scala-way.

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

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

Ага, в программировании топить за старую школу == «не хочу учить новое»

получил по щщам и больше не шумит

пацаны, я короче шел сегодня по авторынку и увидел хипстера в майке «Java OOP 4EVER», ну я подскочил и резко переебал его в щщи с вертушки, и пояснил криком «не люблю наследование и полиморфизм», потому что я угорел по scala, пацаны, дух старой школы только в typesafe, где ебашатся по статической типизации, имплиситам, где ебут в рот жабу и индусятину, и срут на шаблоны проектирования! только scala, только хардкор! юнити скала и лифт! пацаны, ебаште оопшников, делфистов, лиспорасов, рубидаров, угорайте на трейтах, любите REPL и Одерского! говорите открыто и смело в лицо! SCALA!

Главное не пытатся писать на скале как на джаве, лучше полностью её забыть.

То то скала так и не взлетела.

Нужно делать всё Scala-way.

Скала-вей он какраз без котиков и шейплесов.

Котики и шейплесы — это недо-хаскель вей.

Скала-вей он какраз без котиков и шейплесов.

«Какраз», таки скала вей — недо-хаскель вей, система типов позволяет.

Много софта написанно без котиков и усе отлично работает. И только недо-хаскелисты считают что правильная скала == недо-хаскель. Одно не понятно, что им мешает юзать собственно хаскель, и не выносить окружающим мозг.

Повальное остуствие либ и прочей экосистемы.

Почитав коментарі, дивуюсь твоїм відповідям, твій профіль хакнули після теми про паролі?

Теоретически можно что-то добавить в эти сеттеры/геттеры, скажем проверку на разрешенные значения и т.п., не меняя клиентов. Правда, DTO должны быть тривиальными по-хорошему, так что тоже спорно.

Практически 99.99% случаев (может кроме либ некоторых) — дикий карго культ со времен первых bean-editors, заэнфорсенный всякими нехорошими либами и привычкой.

Пользовал во многих проектах просто поля, проблем особых технически не было (включая долгосрочную поддержку). С людьми сложнее. Джуны скулили что в книгах по-другому написано; мидлы жаловались на привычку тыцнуть «.get» и ждать подсказки IDE.

Потом Котлин пришел на бек-энд и скрыл это безобразие из кода в байткод.

Теоретически можно что-то добавить в эти сеттеры/геттеры, скажем проверку на разрешенные значения и т.п

Хто так робить? Ви таке бачили? Я — не бачив. В тому й суть. Але он купа людей імітують собою тих мавп, жодну з яких не поливали водою, але вони все одно пиздять інших щоб не лізли за бананами.

Советую познакомится с хайбернейтом или спрингом, много интересного там

Я зараз про ентерпрайз код який ми тут всі пишемо.

много интересного там

Дякую дядь, я асенізатором не хочу працювати поки що.

А что в

ентерпрайз

ОРМ не используют ?

Да не обращай внимания, он дивный.

Что именно в Спринге релевантно? Вроде там уже не там много на сеттеры/геттеры заточено.

Хайбирнейт — да, хотя ИМХО как раз пример как делать уже не нужно.

как раз пример как делать уже не нужно.

Почему делать не нужно ?

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

Делает его пользу огромной, если проблема выучить хайбер так и надо говорить, чукча не читатель

если проблема выучить хайбер так и надо говорить

вижу знатока тонкостей хайбера. Прибирал за такими много.

Прибирал за такими много

))))))

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

что орм заменяет знания базы, это не так.

Зависит от сложности приложения.
Если User user = em.persist(new User());
То заменяет полностью, даже знания сиквеля не нужны.

но только такие системы никто не создает

Судя по каментам здесь, многие только такие системы и пишут.

Проблема в том, что БД отвечает на задаваемые вопросы, а ОО описывает взаимодействия между объектами. Связать два этих концепта — это сложная задача сама по себе.

ОРМ работает когда у вас очередной CRUD и почти анемичная структура классов, т.е. в 95% случаев. В остальных 5% вас ожидают сексуальные приключения нетрадиционного характера с ОРМ там, где можно было бы справиться одним-двумя (возможно нетривиальными) SQL запросами.

Лол.
Все ровно наоборот.

Когда

у вас очередной CRUD и почти анемичная структура классов, т.е. в 95% случаев.

Как раз таки можно изи прожить на обычном сиквеле.

А вот когда

В остальных 5%

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

ОРМ там, где можно было бы справиться одним-двумя (возможно нетривиальными) SQL запросами.

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

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

Угу, железо дешевле разработчиков..

Открою тебе тайну, великую и страшную — орм позволяют выполнять нейтив запросы на изи

А сама орм зачем, если в ней писать нейтив запросы?

А сама орм зачем, если в ней писать нейтив запросы?

Вот мы и пришли к тому, что большинство ярых критиков орм не понимает вообще что такое орм.
Базовая концепция Обжект Релейшншип Маппинг — всеголишь конвертация табличных данных в объектное представление графа, а форейн кейв и джойн таблиц — во вложенность объектов. И обратно. Превращение РезалтСета на 100500 колонок в граф объектов.

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

Более того, идущая в коробке с ОРМ способность персистентных объектов флашить свое измененное состояние назад в базу — тоже не является обязательной, и вы можете использовать жпа/хиб не вынимая из жпа ни одной менеджед ентити, обходясь только не-ентити представлениями сущностей, основанных на поджо классах без @Entity и кастомном маппинге. Да и вообще тот же жпа вполне можно использовать как не-бойлерплейтный jdbc2.0, довольствуясь только императивными транзакциями, стрингами запросов и байндингом параметров.

А все квери ленгведжи, генерирование запросов на базе нейминга методов в спринг дата жпа, и ем.файнд(Кет.класс) — это просто утильный сахар, вишенка к основой идее.

именно эту задачу ОРМ прекрасно выполняет

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

Далее, БД — это обычно огромный массив данных, и чисто теоретически, ОРМ должен будет выгрузить большую часть этих данных в память процесса. Что тоже плохо.

Базовая концепция Обжект Релейшншип Маппинг — всеголишь конвертация табличных данных в объектное представление графа, а форейн кейв и джойн таблиц — во вложенность объектов

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

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

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

Селекты в ручную это скорее всего n+1 select problem и это буквально первые грабли на которые джуны наступают в ORM.

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

только решения работают для случаев одного джоина.

Лично проверяли?
У меня тут приложение где графы джойнов бывают по 10+ а то и 20 и более, и все прекрасно работает.
Видимо, мой хиб не в курсе, что он не должен работать.

кол-во ... и лишних данных.

А что такое «лишние данные»?

n+1 select problem

Я сейчас напишу страшное, за что меня могут избить в темном переулке.

Н+1 не такая уж и проблема.

Более того, эта «проблема» возникает каждый раз, когда в @Entity появляется 1+ коллекций @OneToMany, что с точки зрения доменной области не является ни удивительным, ни плохим.
В таком случае хиб не способен вытянуть более одного отношения через джойн, и все остальные будет тянуть через селект.
В теории наверное это ужасно, но на практике мы проблем не испытываем.

Кроме того, вообще вся лейзи инициализация вызывает +1 селект, поэтому страх Н+1 селекта и попытка какой-то абстрактной борьбы с ним видится мне борьбой с ветряными мельницами.

Более того, эта «проблема» возникает каждый раз, когда в @Entity появляется 1+ коллекций @OneToMany, что с точки зрения доменной области не является ни удивительным, ни плохим.
В таком случае хиб не способен вытянуть более одного отношения через джойн, и все остальные будет тянуть через селект.

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

Вполне способен

По состоянию на сегодня, насколько я знаю — нет, не способен. Не в том смысле, что это физически невозможно, а в том, что он так не работает.
stackoverflow.com/...​le-onetomany-associations
Или пруфлинк, что способен.

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

Но в любом случае, даже несмотря на принципиальную техническую возможность, так лучше не делать, так что можно считать что все равно Н+1.

Эту задачу он выполняет крайне хреново

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

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

Тут просто фейспалм. Внезапно, чтобы приложение работало с данными из базы, их в принципе необходимо передать в память приложения. Если «сова против», можете писать ентерпрайз приложения на пл/скл прямо в базе, удачи, чо :)

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

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

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

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

Если «сова против», можете писать ентерпрайз приложения на пл/скл прямо в базе, удачи, чо :)

Их так и пишут.

Полная чушь, они как раз ими и являются.

Не-а. Ваши объекты — не более чем обертки над обычными структурами. Никакого своего поведения у них нет

Это только подтверждает что вы в принципе не понимаете даже то, какие проблемы орм должен решать, куда там уже до того, как они работают.

ОРМ решает проблему написания CRUDов — быстро, грязно, почти ООП. Можно расставить пальцы веером и сдать курсовую.

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

дядя ну если ты Senior Expert C++ Developer
то зачем вообще пробовать говорить про хайбернейт, все что ты написал про хайбернейт абсолютная ложь.
В Хибере можно и 10 джоинов сделать и все в одном единственном SQL запросе

Хибернейт в дополнение к базе, что делает его пользу сомнительной.

Его польза действительно сомнительна, если данные сравнительно плоские. А если данные объединены ФК в графы по 20-30-40 таблиц, то без жпа, вперед, через plain old jdbc прямиком в дурку.

спринг со времен аннотаций какраз вполне без гетеров работает.

Работает и без, но рекомендуют вешать аннотации именно на гетеры.

Хто так робить? Ви таке бачили? Я — не бачив.

Бачив. Інколи навіть має рацію, але immutable + builders все ж краще, IMHO

колекціі, до речі, буває зручно в геттері обернути в Collections.unmodifiableXXX щоб запобігти myDto.getDataList.add("sneaky-sneaky") по всьому коду

Так, в мене для цього геніальна конструкція

return list == null ? Collections.emptyList() : Collections.unmodifableList(list);
Глобально и надёжно.

Інше питання нашо воно треба. Якщо кому треба буде шось поміняти то рефлексію бахне і все.

Такий собі китайський замок на штахетному заборі.

если рефлексию кто увидит на код ревью то будет много вопросов

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

в сеттерах ты скрываешь логику инициализации переменной или же логику изменения состояния объекта

Це можна винести в контролери, які, власне, і мають відповідати за зміну стану і проблема пропадає.

Контроллеры — веб что-ли? А что если не только веб? Веб конторллеры должны вебом заниматься, а не поддержкой инвариантов.

Контроллеры — веб что-ли?

До чого тут веб? Контролер це логіка, що змінює стейт системи.

Цікаво, але не дуже зрозуміло. Що таке «система» в даному випадку? Мої мікросервіси stateless, скажемо.

Система це сукупність логіки, правил, що вирішують бізнес задачу юзера. Якщо система без стану, то там і нема стейтфул моделі, а значить і проблеми топік стартера =). Чи не так?

Ну вот в там где логика на входные данные которые кладут\ложат в переменную, там и инкапсулируют эту перменную, класс с логикой сам решает в каком виде возвращать эту переменную, переколбашивать или тупо вернуть как есть, ведь завтра уже может быть другая логика.
А если это DTO, то понятно дело не должно быть там никакой логики, поэтому можно тупо ставить паблик поле и не парить мозги.

Я роблю так:

class AccountController {

AccountDTO dto = Json.parseAccount(message.body);
dto.validate(); //throws inside specific error;

Account account = accountDao.getById(dto.id);
account.update(dto);

}

Це у випадку якщо мені потрібно модифікувати багато полів. Якщо декілька, то так:

account.name = dto.name;

За валідацію відповідає AccountController. В ньому я делегую validate() в DTO клас, просто щоб було легше читати логіку самого контролера. Але глоабльно за валідацію завжди відповідає AccountController і він повинен зробити перевірки і трансформації, якщо треба. Модель ні за що не відповідає і просто перекладає, віддає поля. Вся логіка в контролерах.

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

А единственный способ, в данном примере создать аккаунт, это rest?

Ні. Це може бути шттп, вебсокет, мктт чи мобайл апі з окремим протоколом.

Или валидация дублируется для каждого механизма?

Зележить від валідації. Деяка дублюється (перевірка вхідних параметрів), деяка переюзається (специфічна до бізнес логіки).

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

Такі штуки бажано виносити в спільний контроллер.

В целом интересны причины не выделять валидацию и кодирование/декодирование в отдельный слой.

Це ускладнює код. Одна справа зайти в 1 контроллер і зрозуміти всю логіку. Інша справа пройтись по ланцюгу з 10-ка таких контролерів.

За валідацію відповідає AccountController. В ньому я делегую

АААААА

логіка в контролерах.

ААААААААААААА

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

Це інший підхід. Він має своє право на існування.

Пожалуй, топовый по абсурдности коммент во всей теме.

логіку в сеттери ? я щиро співчуваю тим кому треба розвивати такий проект :D

Ну как бы для этого проперти и создавались — на вид как переменная, а работает как функция. Что плохого то?
Хотя лично я не помню уже когда видел логику в сеттере :-)

як логіка буде добавлятись то сеттери будуть розбухати і рости вшир,а краще щоб проект ріс в глубину, паттерни заюзати — command, strategy, etc
бо потім буде піпєц, imho

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

так, але якщо розбуханіє іде в межах одної логічної групи (припустимо одна оперaція бізнес логіки)
і то нада «дєржать ухо востро» бо пєсєц підкрадаєтся незамєтно
а якщо декілька бізнес операцій лізуть по одному жирному класу, точно жди біле звірятко на проекті

краще якщо проект росте packages+classes по SOLID принципу
так простіше викидати стару логіку і добавляти нове
ну і тестувати

логіку в сеттери ?

Классы со сложным состоянием? Не слышали? Information expert pattern, нэ? Атомарная и независимая поддержка консистентности объекта, обладающего сложной структурой и сложными бизнес рулами? Ченжлог объекта, нэ?
Крудописцы, блин. Кет кет = нью Кет. Кет екстендс Пет блин.

йо бро, take it easy :D, we got it, живі люде тут
панімаю шо баліт, но з людьми нада помягше :D

Черные дыры? Всемирный эфир? Одни ли мы на этом свете? Какое все это имеет отношение к контексту топика? Примерно такое же, как и «классы со сложным состоянием»

Какое все это имеет отношение к контексту топика?

Прямое, тебе не понять.

Ага, щас, рабочий проект на гитхаб выложу и ссылку скину, лол :)
Во-первых, что именно вас интересует, а во-вторых, зачем это мне? :) Какой-то маааленький кусочек могу и показать, измененный естественно.

Классы со сложным состоянием? Не слышали? Information expert pattern, нэ? Атомарная и независимая поддержка консистентности объекта, обладающего сложной структурой и сложными бизнес рулами? Ченжлог объекта, нэ?

Продемонстрируйте примеры того, о чем вы говорите в своих комментариях, пожалуйста.

Почту дайте, покажу пару кусочков.

это *ндусы придумали, им за количество строк кода платят.

другана кум ненавидить двє вєщі в жизні —

*ндусы

і расізм :D

Безусловно это нарушение инкапсуляции, но это нарушение нужно для работы библитек и фреймворков, которые сериализуют объект. Например, для разных ORM (Согласно спеке JPA необходимо объявлять геттеры/сеттеры), либо для того же Jackson. Кроме того, многие фреймворки и бибилоетеки (Тот-же Hibernate) делают прокси объекты (например, для лейзи лоада) и для доступа к приватным полям нужны геттеры сеттеры.

Еще, ниже видел обсуждение на тему «Почему бы совсем не отказатся от гетеров сетеров и не сделать поля публичными». Отчасти уже написал ответ выше: потому что прокси паттерн без методов использовать нельзя никак.

Через рефлексию хехе

это просто костыль чтоб рефлексию не ускорять

либо для того же Jackson

Ніт.

Ну вот зря, ибо лазание к приватным полям через рефлексию ещё большее зло

Тому є public
(Спрінг з переляком дивиться у вашу сторону)

мені здається, коли створив клас, додав 3-4-5 поля, потім нагенерив IDEA-єю чи lombok-ом конструкторів, геттерів/сеттерів, еквалсів-і-хеш-кодів, то мабуть можна обійтися) хоча особисто мене просто напрягає перегенерювати кожен раз скажімо еквалси-і-хеш-коди, коли мінається структура)) тому юзаємо lombok)

але є ряд класів, особливо коли велика доменна область, 100500 різних модельок, то хочеться, щоб в самій модельці були додаткові методи, які вже мають якусь мінімальну «логіку» + не давати наліво і направо доступ міняти обєкт всім кому попало з будь якого місця аплікації)

ну якийсь такий приклад скажімо) як його можна було би краще зробити?

public class Prices {
    private BigDecimal price1;
    private BigDecimal price2;

    public Prices (BigDecimal price1, BigDecimal price2) {
        this.price1 = price1;
        this.price2 = price2;
    }

    @Transient
    public boolean isPrice1MoreThanZero() {
        return isPositive(this.getPrice1());
    }
    
    @Transient
    public boolean isPrice2LessThanZero() {
        return isNegative(this.getBase());
    }

    @Transient
    public boolean isPrice1Zero() {
        return isZero(this.getPrice1());
    }
    
    // copy-paste: price2
    
    // getters
}

А нащо той Priсes взагалі потрібен? Може поміняти на sova та globus — так зрозуміліше буде?

Буває таке, що є декілька джерел інформації, які надають для прикладу ціну і ще 2-3-4 різних коефіцієнти. І на основі цих даних приймається якесь рішення)
Коли читаєш такий код 6-місячної давності, хочеться його «читати», а не розбирати по новому, що означає сова, а що глобус)

перший код згенеровано з якогось DSLя , другий код написано вручну :)

В принципі питання з OOD, яким насправді дуже мало хто володіє, а чи потрібно OOP для DTO. А для Model ?

В принципі питання з OOD, яким насправді дуже мало хто володіє

Судя по этой теме — куча народу даже не знает что это за 3 буквы.

Анклбоб предлагает делать различия между структурами данных и классами. Вот это все геттерно-сеттерное говно — это не классы, это структуры данных. Поэтому OOD к этим вашим DTO применим настолько же, насколько, скажем, нисходящий дизайн — т.е. совершенно ортогонален.

Старый пёс показывает молодому, как закапывать косточку:
— Я не знаю, зачем это надо. Но каждая собака должна это уметь.

Харить що люди мало того що ведуть себе як ті собаки, так ще й інших вчать.

Тобі ото «харить», а от як жабі дати зрозуміти що в світі існують типи даних типу «не суй туди рило, паскудо», які є масивом байт, але то її сношати на мало б окрім як спеціальними методами. В остальних випадках — лише читати, писати, та не більше.

Чому int може бути примітивним типом, а byte[] - не може, чи то похідні від нього?

Я розумію, що Java була створена щоб спростити C++ та не дати вистрілити собі в ногу. Але воно вже все настільки складне, що треба створювати її заново, щоб не дати повіситись.

PS. Я взагалі не розумію, ЧОМУ треба писати гетер та сетер, ЯКЩО в Java це не є примітивними грубо кажучи шматками неконтрольованої пам′яті, це повноцінні Object, і для їх отримання та запису всередині JVM паше не те що гетер-сетер, а цілий ClassLoader, із кешуваннями та мультипоточністю. Що заважає як в древнючому Делфі, замість написання власних гет/сет просто знати що існують системні, та дати можливість зробити їм Override на рівні коду.

Можна подумати, той самий контролер доступу private не є тим самим оверрайдом? Нащо я повинен вигадувати щось інше — написав private — то приват, написав protected — ууупс, а у жаби вже баго-фічі лізуть, коли давно вже варто виправити старі косяки наслідування.

Type inference — то ми можемо. А б-дське написання 9 строк коду замість однієї — то жаба задавить прибрати.

. Але воно вже все настільки складне, що треба створювати її заново

= так уже и многократно — скала и котлин, последний андроидам полюбился.

Відмовився від гетерів і сетерів 5 років тому. В основному через:

— Не юзаю хібернейти, спрінги і відповідно не потрібні всякі проксі, які реквестують гетери/сетери;
— Купа бойлерплейту, який ускладнює читання коду. Ломбок — взагалі боротьба не з причиною а з наслідками. Це як до велосипеду додати 3-тє колесо, а потім його підняти, щоб не заважало;
— Стало набагато приємніше кодити;

Пруф — github.com/...​core/model/auth/User.java

Основний недолік — не можна заюзати в стрімах посилання на поле. Але це легко обоходиться старим добрим лупом.
Зараз ми запускаємо новий продукт. В ньому пробую інший підхід — «public final» для всіх полів. Тобто імутабл. Поки що подобається набагато більше. Але при адейті доводиться писати більше коду + оверхед по перформансу.

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

Можливо я вже відстав. А як же проксі хібера які роблять фетч у момент гета?

Фетч ЧОГО? Кожного поля даних окремо? Чи таки ПОВНОГО набору даних?
Тому маленькі класи даних — краще залишити POJO, а от змінну яка володітиме екземпляром — то вже можна і на гетер повісити.

Як на мене, то все намагання натягнути сову на глобус. Мені, як програмісту, набагато простіше самому розуміти, КОЛИ я хочу взяти дані, і зокрема, коли відв′язати екземпляр даних від обслуговування круд-фреймворком.

Чому так: у більшості випадків дані потрібно читати, а не писати. Але від того вони менше оперативи аж ніяк не займають. Якщо даним не потрібно тримати постійно актуалізацію, а це майже 100% і неможливо через клієнт-серверну модель, то саме відв′язавши об′єкт від фреймворку я надаю йому право бути зжертим збирачем сміття.

Виключення — об′єкти, які потребують кешування. Але то окрема тема.

Нарешті слова реального практика а не ентерпрайзного раба. Аплодую стоячи.

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

Для себе не бачу бенефетів. А для бізнесу це додаткові ризики.

Тобто імутабл
оверхед по перформансу

Ну якщо ти софт для кавоварки пишеш, то можливо.

Кавоварка це з одного боку, а з іншого сервер з 50к рек-сек. Згоден, що для більшості проектів перформанс не проблема, для їх 1 рек-сек в максимумі.

Пруф — github.com/...​core/model/auth/User.java
public Profile profile;

//used just for tests and serialization
public User() {                  // no profile assignment here
public User(....) {              // no profile assignment here too
//used when user is fully read from DB
public User(...., Profile profile, ...); // here it is, at last.

public isUpdated(long lastStart)         // public call, profile usage is 
                                         // not declared explicitly
....private isDashUpdated(lastStart)     // internal call
........profile.dashBoards               // internal usage, no nullcheck
== highly NPE-unsafe

не, ну понятно, «у нас все работает», «а нам норм», ага.

Це 3 різні флова.

User() // no profile assignment here
public User(....) { // no profile assignment here too

public User() {
this.profile = new Profile();
}

User(String email, String passHash, int orgId, String region, int roleId) {
this();
}

public User(...., Profile profile, ...); // here it is, at last.

Це окремий випадок, для відновлення профайлу з БД. Коли юзер філди і профайл лежать в окремих полях.

Інакше кажучи цей код NPE free. (Пруф — клікаєм правою кнопочкою по полю і дивимось „Value write”)

Всі називають це «інкапсуляцією».

Не все. Просто джава очень популярная технология и поэтому очень много шлака опубликовано. Пока профессионал будет готовить хорошую статью, очередной тренер вайтишников успеет свою опубликовать и на конференциях повыступать. Вы вот можете придумать сходу 2-3 примера «правильной» инкапсуляции, которые будут понятны многим (особенно джунам) и не противречивы (не выглядеть как ненужное усложнение)?

Але чим це відрізняється від

Возможность переопределять методы (сеттеры и геттеры), а так же спекой джава бинс, которая позволяет использовать дженерик подходы для работы с данными (например сериализаторы и презентейшн)

Да изи же — берём какой- нибуть объект внешнего мира в виде сокета или потока вывода к которому как попало нельзя обращатся — и пишем вокург него абстракцию.

Да изи же — берём какой- нибуть объект внешнего мира в виде сокета или потока вывода к которому как попало нельзя обращатся — и пишем вокург него __абстракцию__.

И у вас получится пример инкапсуляции или абстракции?

Да, в полне — если мне нужно только писать в сокет текстовую информацию, я предоставлю только методы для отправки текста.

Да, в полне — если мне нужно только писать в сокет текстовую информацию, я предоставлю только методы для отправки текста.

Пойдите и почитайте что такое инкапсуляция.

Мне то зачем, я ассенизацией оопшни не занимаюсь.

Мне то зачем
Ага, в программировании топить за старую школу == «не хочу учить новое»

---

я ассенизацией оопшни не занимаюсь.

Учитывая ваши коменты в этой теме это логично: вы не очищаете, а производите :)

ООП — это старое, фп — это новое. Всё логично. ООП-прогеры в моём коде точно с пол пинка не разберутся, потому что от ооп там взято то что всё фп реализовано жвмными классами, а всё остальное — нечитаемо без понимания теорката/алгебры хотя бы на базовом уровне и понимания имплиситов на прошаренном уровне. Для них мой код точно будет Г в которое лучше не лезть, но плохим, и тем более говнокодом он от этого не станет.

ООП — это старое, фп — это новое. Всё логично.

Ну хоть бы в вики заглянули для начала :)

Для них мой код точно будет Г в которое лучше не лезть, но плохим, и тем более говнокодом он от этого не станет.

Не станет говнокодом, а уже стал. Код настолько хорош, насколько легко его понять (с минимальной подготовкой или вообще без любой подготовки). Одним из селлинг поинтов ФП являлось то что программы получаются понятными даже людям без профильного ВО (в основном из-за декларативного стиля).
ООП как раз направлен на то чтобы улучшить понятность кода для всех, а не только его аффтара.

Одним из селлинг поинтов ФП являлось то что программы получаются понятными

Абсолютный маркетинговый баллшит и чушь собачья в одном лице, не имеющая под собой никаких оснований. Не шаря, фп код можно прочесть с трудом, а изменить нельзя — компилятор по рукам надаёт. Я уже неоднократно наблюдал картину: приходит джавист бывший в компанию, натыкается на деривацию инстансов тайпклассов, котов, ридер монады и прочие прелести и через 2 месяца сваливает.

Это утверждение справедливо только для тех кто в фп действительно шарит — меньше кода, больше сути и надёжности. ООП не направлено на повышение читаемости, во всех мейнстримных языках приложены все усилия чтобы расставить возможности наступить себе на грабли. Кроме того, чтобы делать совершенно элементарные вещи надёжно и как следует, в этих ваших джавах, сишарпах, плюсах и питонах нужно писать кучу болерплейта и воротить кучу архитектурных излишеств. Чем больше и сложнее архитектура, чем больше туда накидано паттернов и прочего оопшного шлака, тем сложнее эту гадость прочитать и понять. Сверху это приправлено абсолютно тупым компилятором который вообще ничего проверить не может и радосно расставляет свои грабли. Это НЕ повышение читаемости, это не благодаря, а вопреки.

Все и каждая из придуманных ООП шных абстракций не имет под собой строгого теоретического фундамента который бы доказательно описывал их свойства, а собственно по этому являются ненадёжными и непредсказуемыми. Вот и имеем, каждый ворочает как хочет, никакого единого стандарта нет. Всё ФП — построено на понятиях из теорката(который собственно и является одним — единственным стандартом) — который был изобретён математиками, и имеет строгое теоретическое обоснования начиная с мизерного количества аксиоматических понятий. Но чтобы теоркатом пользоватся, эти теоретические обоснования надо знать, без этого ничего не получится.

Там этого теорката гулькин нос, с десяток страниц энтри-левел книжки. Зато трындежа на целый, не к ночи будет упомянут, ncatlab.

с десяток страниц энтри-левел книжки

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

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

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

Одним из селлинг поинтов ФП являлось то что программы получаются понятными даже людям без профильного ВО

По-моему, это про сиквел говорили /and look where that’s got us/ или, прости господи, про пролог

Про lombok уже писали?

Не, не слышал.

Ну тогда настоятельно рекомендую всем джавистам: projectlombok.org

Вау нічого собі яка ліба, щас ми зробимо магію і викинемо половину кода

@ToString
@EqualsAndHashCode
@Get
@Set
@Bean
@Entity
@Zbs
@FuckThisFuckingJavaShit
public class Vasya {
Прогрес!

А можно просто @Data или @Value )

Можна просто на котлін перейти там датаобжекти є.
А можна взагалі на js там люди собі такою фігнею не забивають голови і цілком успішно проекти роблять.

Все можно, отстань уже от старушки

Там все це можна дуже аккуратненько зробити якщо треба, але все заховано ;)

Włodzimierz Rożkow веб-макака без претензій

А так і не скажеш.
Досить тролити, в коментарях вже достатньо розжували.

Досить тролити, в коментарях вже достатньо розжували.

Мій тред, шо хочу те й роблю дядь. Закрий табу і не читай.

Окей. Тоді називайте цей тред «хто хоче посратись з приводу java-verbosity», бо хтось змарнував свій час намагаючись допомогти примітивному тролю.

Я не просив допомоги дядь. Я конкретне питання задав (а саме необхідність get/set в анемічних моделях) і хочу діскаснути цю тему. Якщо тобі не подобається то проходь далі. В нас тут вже 100 каментів, люди не дурні.

В нас тут вже 100 каментів

Оце так показник! З них, правда, половина належить ТС.
Але день пройшов не даремно.

З них, правда, половина належить ТС.

40 із 130 дядь. І це я людям відповідаю по темі.

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

@SpringBootApplication
@EnableDiscoveryClient
@EnableScheduling
@EnableAsync
@EnableConfigurationProperties
@PropertySource("mapping.properties")
@EnableAutoConfiguration
@EnableFeignClients("me.rozhkov.integration")
@EnableRetry
@ComponentScan({
        "me.rozhkov.app"
})
public class Application {
}

Взято з реального проекту.

да, в блокноте такое не порефакторишь

А що в тому поганого? Якщо це клас аплікухи, звісно там зосереджена бюрократична частина, що адаптує аплікуху до зовнішнього середовища. Я б туди ще 100500 коментів докинув, на випадок якщо якомусь «мідлу» захочеться щось покрутити — хай почитає, може передумає.

Джавистам лучге посоветовать мигрировать на более вменяемый язык — groovy/kotlin/clojure/etc
сделать хуже «гирлянды» из гетеров\сетеров — нужно еще постараться, но у ломбок это получилось

а что именно не так с lombok?

www.oracle.com/...​a/simple-142616.html#4078

By removing all this baggage, Java becomes remarkably context-free. Programmers can read and understand code and, more importantly, modify and reuse code much faster and easier.

т.е. „read and understand code”, а не гадать что эта х-я делает (почитайте их багтрекер, на что люди жалуются)

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

гадать что эта х-я делает

это одна из рутинных задач разработчика, если не писать одно и тоже каждый божий день.
P.S. lombok очень даже стабильный. Багтрекер наполнен фича реквестами и адаптацией под последние версии Java. Серйозных багов я там не увидел.
Ну это все имхо.

что именно не так с lombok?

С ломбоком все в принципе хорошо. Не так — с мозгами у фанатов мертворожденных

groovy/kotlin/clojure/etc

Якщо юзати ООП — то це погана ідея, так як override не працює з полями. Але, якщо крім інкапуляції, відмовитись ще й від наслідування і поліморфізму, то норм :) Ось приклад

public class Main {

    public static void main(String[] args) {
        class A {
            String name = "A";

            String getName() {
                return name;
            }
        }

        class B extends A {
            String name = "B";

            String getName() {
                return name;
            }
        }

        A a = new B();
        System.out.println(a.name);
        System.out.println(a.getName());
    }
}

Output:
A
B

Ти це перевіряв? Особисто я ніколи, в мене було б написано private String name = «A»;
А якщо воно йде на оверрайд, мабуть зловив би ворнінгів.

Отличный пример того, как в купе с неправильным пониманием инкапсуляции следует неправильное понимание наследования и полиморфизма. Ваш код нарушает L (и, вероятно, O) из SOLID.

Практические советы:
— class должен быть либо abstract, либо final;
— в абстрактных классах должны быть абстрактные методы;
— неприватные неабстрактные методы абстрактных классов должны быть final.

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

Я так понимаю в Java нет свойств, тут раздельно методы доступа, в C# есть свойства, но из-за огромного количества бесполезного кода в таких ситуациях там ввели autoimplemented properties, string id {get; set;}, поле создается на уровне IL, скрыто от разработчика.
А т.к. такое свойство ничем не лучше просто поля string id; , то в последнее время многие программисты топят просто за использование открытых полей.
Но повторюсь, это только в такой ситуации, если например нужен открытый геттер и закрытый сеттер — то свойства помогают.

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

в последнее время многие программисты топят просто за использование открытых полей

Хто? Перший раз чую.

Нє я розумю в js воно так з коробки працює і всім норм. Але в джавці не чув.

Есть старая презентация Антона Кекса «Как нам спасти яву», где затрагивается абсурдность устоявшихся «бест практик».

1. Не сделаешь immutable без getter c private полями. Кроме как рид онли при отсутствии сеттеров, геттер дает возможность возвращать копии мютабл обьектов.
2. Не забываем про прокси, если обьект дает прямой доступ к своим полям, то про lazy в JPA можно забыть.
3. Все что было сказано до этого может казаться незначительным до тех пор, пока с этим не столкнешься.

Не сделаешь immutable без getter c private полями

Часто бачили иммутабл в крудах? Я зараз про конкретний приклад який використовується в 95% ентерпрайз коду на джаві.

Да. а что там в 95% энтерпрайза — мало волнует

Я не про ваш рокет саєнс на окремо взятому проекті, я про реалії ринку.

Именно так и работаем. Immutability дает очень много преимуществ, как технических так и таких как улучшение читаемости кода. Можете погуглить как много дает Immutability. Советую почаще использовать.

Воу воу воу, палєхчє, може зразу на кложу пересісти?

Именно так и работаем. ___ дает очень много преимуществ, как технических так и таких как улучшение читаемости кода. Можете погуглить как много дает ___. Советую почаще использовать ___.

Паста готова

Некоторые поля могут быть только read-only, но могут изменяться внутри класса/пакета.
В свифте есть например private(set), даже в старом как говно мамонта objective-c есть readonly, а в джаве — это можно делать только через сеттеры/геттеры.

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

А как изменить final-поле внутри класса? Только давайте без рефлексии

Я про то, что рид-онили поле должно быть рид-онли для всех, и отсутствие паблик сеттера не делает поле рид-онли.
а final поле внутри класса, как правило, менять не нужно )

Задача сделать такое поле, которое будет immutable для внешних классов/пакетов, но mutable внутри самого класса/пакета.
Пример:

Swift

class SomeClass {

private(set) var someVar1: Int
private(set) var someVar2: Int
private(set) var someVar3: Int
private(set) var someVar4: Int

.......

func doSomeWork() {
someVar1 = 1
someVar2 = 2
.........
}
}

Java

class SomeClass {

private int someVar1;
private int someVar2;
private int someVar3;
private int someVar4;

public int getSomeVar1() {
return someVar1;
}
public int getSomeVar2() {
return someVar2;
}
public int getSomeVar3() {
return someVar3;
}
public int getSomeVar4() {
return someVar4;
}

public void doSomeWork() {
someVar1 = 1;
someVar2 = 2;
.........
}

}

Где больше бойлерплейта?

Херовая задача просто

если поле класса надо менять только внутри — сделай боксинг значения в приватный клас

Но опять таки, зочем, эго поднять?

Но опять таки, зочем, эго поднять?

Пример — android.googlesource.com/...​droid/view/View.java#6955

Если бы в джаве было что-то вроде «private(set)» — не надо было создавать лишний геттер.

если поле класса надо менять только внутри — сделай боксинг значения в приватный клас

... , можно написать кастомный annotation processor, можно подключить дофига либ типа ломбок — это все лишний бойлерплейт, есть примеры языков где это решается намного более лаконично и без подключения third party либ.

файл на 15 тыщ строк 😳

Новый инстанс создать хехе

рид-онили поля в яве должны быть final

Та ты шо.
Приватное нефайнал поле, которое мутируется внутри, но не доступно для мутации снаружи, при этом доступное для получения.

Всі називають це «інкапсуляцією»

Це не має жодного відношення до інкапсуляції як такої. І ніхто це так не називає.

Почитайте про специфікацію java-beans
en.wikipedia.org/...​eans#JavaBean_conventions

Тепер уявіть, що ваш клас працює у фреймворку, який для вашого класу згенерував проксі, що відслідковує зміни полей (для аудиту, логування, валідації, персистенсу або з будь-якою іншою метою).

А тепер подумайте, чи можливо це зробити без геттерів/сеттерів.

А щоб зменшити кількість boilerplate, є багато інструментів, які дозволяють вам не писати дефолтні реалізації для геттерів/сеттерів.

Тепер уявіть, що ваш клас працює у фреймворку, який для вашого класу згенерував проксі, що відслідковує зміни полей (для аудиту, логування, валідації, персистенсу або з будь-якою іншою метою).

Если, что, то JPA замечательно работает без get/set, отслеживает все изменеия, персистит, и валидирует.

2.1 The Entity Class
...
Instance variables must not be accessed by clients of the entity. The
state of the entity is available to clients only through the entity’s methods—i.e., accessor methods (getter/setter methods) or other business methods

JSR 338: JavaTM Persistence API, Version 2.1
download.oracle.com/...​1-fr-eval-spec/index.html

Може працювати без них? Так. Може відслідковувати зміни? Ні.

Вы знаете как hibernate работает dirty checking ?

Може відслідковувати зміни? Ні.

Можливо, ми маємо на увазі різні речі. Так, якщо окремо зберегти початковий стан, то можна перевірити потім що змінилося. Але це не відслідковування змін об’єкта (уявіть, наприклад, що поле змінилося декілька разів до flush-а):

Може працювати без них? Так.

Але це вимагає вдвічи більше пам’яті та неефективно з точки зору навантаження на CPU (перевірка кожного разу УСІХ полів нерідко складної структури даних).
Що і є наслідком:

Може відслідковувати зміни? Ні.
Так, якщо окремо зберегти початковий стан, то можна перевірити потім що змінилося.

да, именно так это и работает, так обеспечивается транзакционность изменений, это unit-of-work

Вы, похоже, описываете случай с proxy/observer/rpc, но это сильно отличается от изначального примера класса с get/set — у вас будет интерфейс, который обеспечит инкапсуляцию нижележащего фреймворка, отслеживающего изменения.

да, именно так это и работает, так обеспечивается транзакционность изменений, это unit-of-work

До чого тут взагалі транзакційність?

это сильно отличается от изначального примера класса с get/set — у вас будет интерфейс,

Фреймворку не треба ніяких інтерфейсів для побудови проксі. Він спокійно зробить дінамічний проксі для існуючого класу з геттерами/сеттерами.
І через нього буде робити усі необхідні йому cross-cutting concerns.

В 99% — ничем, тут нет инкапсуляции.

Если вопрос — «зачем так делают», то ответ банален — «кто-то где-то когда-то» сказал, что нужно именно так, и все. Сами думать люди, как правило, не умеют.

В реальности — под инкапсуляцией понимается разделение:
— фактической реализации (как именно хранятся данные)
— интерфейса для работы с реализацией

но такое, разделение — это уже высокие материи, которые любят называть паттерном «фасад», добавлять кучу интерфейсов и прочей не нужной лабуды

1. Без get и set методов не выйдет банально переименовать внутренюю переменную во время рефакторинга. В случае переименования переменной get\set методы тоже следовало бы изменить, но код хотя бы будет компилироваться.
2. get\set могут работать с типом интерфейса (List вместо ArrayList, например), что даёт множество преимуществ.
3. В get\set методы можно добавлять код. Хотя этого лучше и не делать, но примеров такого кода в крупных легаси кодбазах предостаточно.

А вообще в большинстве случаев лучше не использовать этот классический Java Bean и и пользоваться веянеями функционального программирования, а именно immutability:
4. Достигается это отсутсвием сетеров и наличием билдера. С открытыми полями такого сделать не выйдет.
Как результат мы имеем типы данных, которые чудесно работают в мульти-трединг энвайрменте.

1. Без get и set методов не выйдет банально переименовать внутренюю переменную во время рефакторинга.

Вы «рефакторинг» в блокноте делаете?

Ок, приклад — ваша праця оформлена в лібу. Вам треба змінити філд, а то й взагалі видалити його. З проперті ви це зробите залишивши інтерфейс ліби незмінним, з філдом завязка на реалізацію і нічого не вдієш окрім як змусити всіх клієнтів оновити версію ліби з попоболлю переіменування по всьому проекту.

ну, т.е. если я удалю фидл, и напишу

public String getName() {
    throw new IllegalArgumentException("field was removed");
}
это решит проблему?
А ну да, код же будет компилироваться, а значит проблемы и нет :)
это решит проблему?

Ні звісно. Я про випадки коли для зворотньої сумісності можна повертати дані забрані по інакшому залишивши депрекейтед проперті на деякий час. Або коли тобі треба змінити внутрішню реалізацію і завдяки проперті клієнти навіть не будуть знати що була зміна і продовжать юзати як і до апдейту.

В примере, что вы приводите — они, скорее всего, узнают про изменение, в результате бага, когда данные, молча, перестанут сохранятся.
Изменение структуры данных — это всегда breaking change.
То, что вы, скорее всего, имеете ввиду — ситуация, когда проерти «переехало» в другой класс, и вместо удаления, пишется «временный» код делегации в get/set. Да, это работает. За счет увеличения технического долга.

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

2. get\set могут работать с типом интерфейса (List вместо ArrayList, например), что даёт множество преимуществ.

Яких?

Классический полиморфизм, вот один из стандартных паттернов:
en.wikipedia.org/wiki/Strategy_pattern

Ви мені патерни не тикайте, я сам розумний. Конкретно де це може знадобитися. Особливо List vs ArrayList. Часто бачили шоб замість аррайліста підсовували шось інакше?

Если это геттер внутри абстрактного типа, имплементации которого в других классах, то да — часто.
Если это обычный POJO, который не участвует в наследовании, то пункт 2 не актуален для этого типа, пункты 1\3\4 всё еще в силе

public class Vasyan {
    public List<Integer> someShit;
}
...
Vasyan petrovich = new Vasyan();
petrovish.someShit = new LinkedLinst<Integer>();

Использовать tight coupling в наследовании, цель котрого поддерживать loose coupling это следующий уровень :)

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

Часто бачили шоб замість аррайліста підсовували шось інакше?

Ну вот в данном случае — как раз «да». Например, Collections.emptyList() или из guava — Lists.asList()

Раскройте пожалуйста подробней вопрос — чем билдер отличается от сеттеров, и почему Вы считаете это ФП?

почему Вы считаете это ФП

Тому шо там багато методів через крапочку викликаються.

Использовали public fields в небольшом проекте, мир не рухнул, из недостатков:
— некоторые рефлекшен приблуды ожидают наличие геттеров/сеттеров;
— на геттеры можно давать method reference а на филды нет;
— если добавляются хелпер методы типа user.addAddress(addr), получается микс прямого доступа к филдам и доступа через методы.

Использовали public fields в небольшом проекте, мир не рухнул

Ооо братішка, перший комент по ділу в темі!

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

А если в классе может быть логика поверх этой переменной

Часто бачили такі класи?

то лучше коенчно через методы работать

В таких випадках краще взагалі get не робити.

Часто бачили такі класи?

Ну если не говнокод то даже не вспомню ща, может правда уже устал :-)
А че гет не делать? Не понял

А че гет не делать?

А нашо?)

Ну если не говнокод то даже не вспомню ща

В тому і суть треду.

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

Если это DTO то там пофиг, у меня щас просто поля и ничего там поверх не надо.

если эти данные завтра перед отправкой в другой обьект надо менять

Новий об’єкт зробимо.

new Wrapper(new OldShit())

тогда уж лучше new NewShit(new OldShit()) :-)

где-то прослезился один Егор Бугаенко

Інкапсуляція в Java

Почему вы считаете что инкапсуляция кончается на отех геттерах и сеттерах? Обычно под инкапсуляцией понимают сокрытие некой реализации в том или ином виде, то-есть в более широком виде

Почему вы считаете что инкапсуляция кончается на отех геттерах и сеттерах?

Тому що бачу проекти на яких отаких класів сотні.

Значить там гівнокод, який робить все паблік чим нівелює інкапсуляцію як таку.

Значить там гівнокод, який робить все паблік чим нівелює інкапсуляцію як таку.

Але ж таких проектів більшість.
Подивіться будь-які туторіали, подивіться свою кодобазу.

Моя кодобаза це те що я пишу) І дивитися на те що писав рік назад не хочеться))

А якщо серйозно, то навала гівнокоду не оправдує продовження написання гівнокоду. Сумно, що багато хто не використовує всі можливості ООП а ляпає по примітивному шаблону.

Сумно, що багато хто не використовує всі можливості ООП а ляпає по примітивному шаблону.

Судячи з всього більшість пацанів і не здогадуються що можна якось інакше робити.

гет сет і в продакшен.

так у нас 30% населения за зеленского голосует, но это же не значит, что это ОК ;) большинство народа работу работают, а ты им задаешь вопросы «зачем?», да некогда им — надо хуяк-хуяк и в продакшен

В першому випадку ви змінюєте стан об’єкта через методи (інтерфейс), а самі дані інкапсульовані всередині об’єкта та є недоступними зовні. В коді який ви привели це виглядає непотрібним і незрозумілим, бо логіка цього об’єкту є дуже простою. А якщо Ви захочете перевіряти ім’я на null, або вік на <1? Або якщо Ви якось захочете модфікувати логіку в классі-насліднику? Використовуючи інкапсуляцію Ви миттєво зможете досягти бажаного, при цьому зберігши безпечність використання классу (Ви знатимете, що Ваш об’єкт міг змінитись через даний список методів), а виставляючи зовні змінні класу просто робите класс небезпечним для використання.
В туторіалах ми це бачимо, бо в туторілах зазвичай не реалізується складна логіка. Навпаки, такі приклади є об’єктами-заглушками для демонстрації всіляких спрінгів і інших комбайнів.
Не хотілось би показувати зверхність, та можливо варто почитати про ООП та місцями книжки Блоха, якщо є такі запитання.
Відповідно, якщо маєте чим заперечити — хочеться дізнатись чим:)

В першому випадку ви змінюєте стан об’єкта через методи (інтерфейс), а самі дані інкапсульовані всередині об’єкта та є недоступними зовні.

Дядь, в прикладах дані повністю доступні ззовні, просто для доступу написаний додатковий бойлерплейт. Це нічим не відрізняється від простих паблік полів.

Відкрий код будь-якого проекту і ти побачиш такі анемічні моделі (часто зверху навернутий hibernate)

Моє питання полягає в наступному — чому всі продовжують писати get/set хоча насправді немає ніякої різниці між public полями?

Моє питання полягає в наступному — чому всі продовжують писати get/set хоча насправді немає ніякої різниці між public полями?

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

Ну а если ты решишь вдруг в один прекрасный момент поменять внутренне представление данных из каких-то соображений?

В вас таке часто буває?

Ну там, скажем, хранить не строку, а массив символов...

)))

В вас таке часто буває?

Важно не то как часто это бывает, а последствия если «таки да». Ну и это только один пример, ниже привели больше (валидации, например и т.п.)

)))

Ну шо ты хочешь от рубиста? :)

последствия если «таки да»

Ну так і напишемо тоді. А до того як — нашо оверінжинирити?

Ну шо ты хочешь от рубиста? :)
attr_accessor :id, :name

www.wintellect.com/properties-or-fields
In Jeffrey Richter’s CLR via C#.

— It’s easy to corrupt a field because there is no validation whatsoever (Jeffrey gives the example of assigning a negative age)
— Properties provide data encapsulation
— Properties have the benefit of allowing data to be validated and cleansed, and can throw exceptions when something is wrong
— Properties can perform other actions such as interacting with a cache or triggering a notification
— Properties can participate in data-binding, fields cannot

Але ж в анемічних моделях ніхто ніколи не пише валідацій.

Більш того, для валідацій є всякі JSR які реалзовуються розвішуванням анотацій і написанням зовнішнього коду.

Ну нам-то, шарпістам легше, get; set; А вони ж реалтно пишуть функції.

Тому що java какашка, С# рулить:

public string Property { get; set; }

Здається що це те саме ло і написати

public string Property;

Але ні, тому що (тут я не памятаю, це правило). Напевно тому що проперті є по своїй натурі задумані для доступу ззовні, тобто коли ти їх пишеш ти вже показуєш що ця штука не внутрішня. Плюс якщо завтра знадобиться додати логіку до сетера чи гетера то це робиться елементарно. А у аипадку з філдом, хз як у шарпі, а от в пхп наскільки я знаю юзаються магічні методи. А магія зло. Також за допомогою пропертів можна визначати хто саме має право сетити, і чи можна сетити взагалі. Наприклад сетити може сам клас вдасник пропертя збираючи його зі своїх внутрішніх даних. Коротше крута штука. Якої в джаві досі нема)))

Тому що java какашка, С# рулить

Ну в котліні теж додали Data Objects які є нічим іншим ніж просто контейнерами з публік полями.

люс якщо завтра знадобиться додати логіку до сетера чи гетера то це робиться елементарно.

В мене в проекті дві сотні класів там немає логіки в get/set методах. В когось є?

В мене наприклад в проперті Age є логіка. Ще в пару місцях в гетері якісь маніпуляції. Також багато де або інкапсульований сетер або його взагалі нема бо він збирає з приватних даних value. Крута штука. Звісно не всюди це треба але для чого одне робити проперті а інше філд, щоб гкмора було? Тому є правило — роби всі публічні властивості класу через проперті і не парся. Те що ви описали це проблема не ідеї проперті а відсутності реалізації на рівні мови програмування.

Ну, думаю є переваги в:
1) Така модель набагато легше підлягає розширенню/зміни логіки.
2) Якщо серед всієї моделі даних один клас — складний і з методами, а інший — простий і з публічними змінними, втрачається одноманітність, користуватись буде важко.

А якщо проект закінчений, в ньому вся модель даних така та на рівні бізнес логіки в трирівневій архітектурі просто прокидуються дані на наступний рівень — ну то це просто схоже на використання болгарки для нарізання сирів.

ака модель набагато легше підлягає розширенню/зміни логіки

Яким чином?

втрачається одноманітність, користуватись буде важко

Суб’єктивізм.

в трирівневій архітектурі

А це шо таке?

1) Якщо у тебе з’явиться додаткова логіка на сет/гет (наприклад, ти для кожного імені в своєму User’і захочеш приписувати ’Sir_’), а у тебе всюди просто публічні змінні. «І шо тоді робить?»
2. ? Якщо тобі в одному класі пакету писати все в змінні, а в іншому юзати методи — норм, то я цього зрозуміти поки не можу, давай агрументацію більше ніж з 1го слова.
3. en.wikipedia.org/...​e#Three-tier_architecture

если один человек, где-то недрах какого-то сеттера напишет + «Sir_», то гарантированно, что другому человеку, прийдется потратить несколько часов своей жизни, на нахождение такого сеттера.

Якщо у тебе з’явиться додаткова логіка на сет/гет

Не з’явиться, де ви її бачили? Я от не бачив ніде.

3. en.wikipedia.org/...​e#Three-tier_architecture

Топ кек, у вас там перший тір це дані, які там валідації, яка логіка в сеттерах альо!

Гетери Сетери можна і в ретурн моделях ставити, при мапінгу моделей даних. Хоча не бачу проблем в моделях даних їх додати, якщо особливо логіки нема просто примітивна обробка полей даних.

А раптом раз в житті станеться той самий випадок, що колись, потім, ну наприклад name зникне з бази, і стане «User_» + id.ToString(), в ось — все інкапсульовано, інферфейс не змінюється, код не перекомпілюється, бо всюди як було call getName, так і залишилось. Теорія працює.

Мій улюблений варіант

public class User {

    private String id;

    private String name;

    public User(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Чим це краще ніж

Map<String, Object> user = new HashMap<>(2);
user.put("id", "42");
user.put("name", "Top Kek");
?

Статической типизацией

Map<String, String> user = new HasMap<>()...

Нет. У class User всегда есть ровно два поля. У Map<String, String> user может быть произвольный набор полей.

Во-вторых, добавьте int age; например.

Во-вторых, добавьте int age; например.
String age = Integer.toString(intAge);

Блін, ви тут хочете спалити всі хаки індіан девелопмента?

public String age;
public String ageType = "java.lang.Integer";
Далі рефлексією кастимо куди треба.

А чому не просто object? Навіщо в стрінг переводити?

Тогда надо так:


public class UserConstants {
static public String NAME_FIELD = "name"; 
static public String AGE_FIELD = "age"; 
....
};

public class UserAccessor {

static public void setName(Map<String, String> user, String name)
{
    user.put(UserConstants.NAME_FIELD, name);
}

static public void setAge(Map<String, String> user, int intAge)
{
    String age = Integer.toString(intAge);
    user.put(UserConstants.AGE_FIELD, age);
}

};


UserAccessor.setAge(user, 42);

Норм.

Але ж можна просто

user.age = 42;

Не я первый это начал

String NAME_FIELD = "name";
...
user.put(NAME_FIELD, "Top Kek");

Шах і мат.

NAME_FIELD нужно в неймспейс засунуть. Что-то типа:

public class UserConstants {
static String NAME_FIELD = "name"; 
....
};
...
user.put(UserConstants.NAME_FIELD, "Top Kek"); 

Турецький гамбіт просто.

Я знаю чого очікувати від типу User, а під капотом

HashMap

буде LinkedList, hashCode і інші структури, щоб уникнути колізій

Я знаю чого очікувати від типу User

Від хешмепа теж можна знати чого очікувати

user.keySet();

У випадку User ти зберігаєш значення, у випадку HashMap ти зберігаєш значення + ключ

dafuq

чим назва поля не ключ?

Тем, что название поля существует только в компиляторе, а ключ — это кусок данных в памяти конечного приложения

І накукуй воно тобі? Просто давай прикинемо, що у юзера не 2 поля, а скажімо 12.
Юзер може створюватися із 3 різних джерел (потрібні 3 різні конструктори), кожне із яких дає інфу тільки по 8 полях, інші скажімо треба заповнити дефолтами за якими-сь алгоритмами.

Питання № 1: Як ти створиш 3 різні конструктори на 8 аргументів типу String?
Питання № 2: Оскільки в тебе нема вибору, окрім як створити конструктор на 12 полів, які шанси що ти запам′ятаєш порядок і нічого не наплутаєш?

А як весело писати под те все тести.......

В разі просто 12 полів даних — то є норма — винести логіку за межі класу з даними. Якщо то потрібно, можна створити статик-методи, чи якись інші довороти, на перевірку даних. Але сам факт, що клас даних не потребує тестування взагалі та не може містити помилок окрім типізації.

Вигода настає, коли в тебе таких класів сотні — їх не потрібно тримати відкритими в редакторі, вони працюють по принципу «створив і забудь», а всі складні процедури з′являються вже там, де йде функціональне навантаження, і звісно ж тестування.

Так, формально це порушує принципи ООП. Але насправді — ні. Принципи ООП працюють для більш масивних класів, що дійсно інкапсулюють логіку. А от дрібні класи даних — то атомарна структура, і якщо чесно, то взагалі не варто було робити їх похідними від Object.

Хороший вариант. Сделайте ещё один шаг вперёд — поменяйте private на public final ;)

en.wikipedia.org/wiki/Anemic_domain_model

Чому ця штука тягнеться роками? Діскасс

Потому что люди пишут CRUD’ы и ничего более

Потому что люди пишут CRUD’ы и ничего более

Чому тоді не позбавитися get/set та не перейти на public поля? Це ж круди та нічого більше.

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

Тобто ніякого профіту від get/set в анемічних моделях немає?

Для аннотаций иногда нужно делать анемичные классы

иногда

не только лишь всегда

значить профіту немає?

Как насчет публичных интерфейсов, например из либы. Использование методов дает большую свободу разработчикам либы, чем использование полей-членов.

От у мене є ліба сдк вконтактє. Там є юзер в нього є фірст_нейм ласт_нейм.
В наступній версї сдк забрали фірст_нейм.

Яким чином методи поможуть? Будуть рантайм кидати? Чим це відрізнятиметься від

final String firstName = "";
Що ми таким чином «інкапсулюємо»? Діскасс.

Це, мабуть, занадто для нашого політичного форума

400 коментів в темі про лінпус для ноута забрали трохи голосів у петі з вовою. Продовжуємо.

Подписаться на комментарии