ReactJS, TypeScript, Micro FrontendsReact fwdays | 27 березня. Долучайся!
×Закрыть

Должен ли объект в Java сериализовать сам себя?

Доброго дня, уважаемые гуру.
У меня есть класс, который содержит коллекцию объектов. Есть статическая функция, которая сериализует объект этого класса в xml-файл. Хотел переделать эту функцию в метод класса, но потом задумался правильно ли это. Подскажите, пожалуйста, могут ли методы объекта сериализовать сам объект и потом получать его обратно из файла? Или же правильнее создать некий внешний класс, который будет сериализовать объект исходного класса?

👍НравитсяПонравилось0
В избранноеВ избранном0
LinkedIn

Похожие топики

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

1. Только сам объект и никто иной знает что нужно сериализировать.
2. Только верхний уровень знает как и во что нужно сериализировать.

Поэтому, в общем, наиболее првильном по практикам (но далеко не всегда на практие) виде, объект должен принимать некую сущность и с помощью общего интерфейса в эту сущность сериализироваться/десериализироваться. Соответсвенное верхний уровень может подпихнуть конкретную реализацию этой сущности в зависимости от нужного ему формата. В более простом виде, объекту передается dictionary куда он может сериализироваться, и потом верхний уровень уже сериализирует этот dictionary в нужный ему формат. На практике же, формат данных в большинстве случаев не меняется, поэтому чтобы не городить кучу сериализаторов, интерфейсов и промежуточных звеньев в цепочке сериализации, которые будут только отжирать память и процессорные ресурсы, можно захардкодить определенный формат и сразу сериализиросаться в него, XML в вашем случае. Потом, чуть что, всегда можно прикрутить универсальность.

Прежде чем городить огород классов сериализаторов, подумайте, что было бы с ЯП если бы в нем не было простого, понятного и изящного метода toString(), который по сути младший брат сериализации для ВСЕХ обьектов.

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

Что будет если вам прийдется делать композицию (а ее на 80% делать прийдется). Это когда метод сериализации сложного обьекта рекурсивно вызывает сериализацию всех мелких обьектов внутри.

не знаю, как в джаве принято, но в общем случае объект может сериализировать себя. Ничего ужасного в этом нет. У объекта есть состояние и поведение. Состояние — закрытая вещь. И оно сериализируется и десериализируется. В общем случае только сам объект о нем знает. Значит он ею и занимается.
Другое дело, что не сам. Желательно, чтобы класс не знал о файлах или способах сериализации. Он «куда-то» складывает значения полей и откуда-то поднимает.
И последнее: любые способы уменьшения работы приветствуются. Например, пометить атрибутами и не писать свой код, использовать стандартные сериализаторы

можно так делать если не собираешся писать супер-пупер гибкую и настраиваимую систему.
Но проще будет посмотреть в сторону JAXB или Simple (simple.sourceforge.net) или других либ

Я не гуру, но комон сенс подсказывает, если у вас один класс строковое представление которого вы хотите сохранить в файл, то ВООБЩЕ пофигу как это делать это будет скорее вопрос религии как лучше/хуже. Другое дело как всем этим пользоваться. Скажем есть два объекта которые пишут разные люди и каждый в своем объекте написал метод сериализации, а дальше эти строки передаются по сети то тут возможны косяки
1) Как представленны в строке ХМЛ свойства объектов как атрибуты тега или вложенные тэги
2) Как эскейпить значения атрибутов
и прочие тонкости которые могут быть. Если метод пишется отдельно в каждом классе то высока вероятность, что даже схожие объекты будут представлены по разному. Если оба класса экстендят класс с методом сериализации то эта ситуация как бы сглаживается, но никто ведь не запрещает переопределять метод и поэтому в этом случае имеет смысл выносить сериализацию за пределы самого объекта.

Создайте вместо статической функции декоратор класса.
Ну и статья по этому поводу:
www.yegor256.com/...omposable-decorators.html

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

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

www.google.com.ua/...pUw&bvm=bv.90491159,d.d24
www.google.com.ua/...giA&bvm=bv.90491159,d.d24
посмотри, это может сможешь больше понимать, что происходит в коде

Думаю, что надо различать два понятия, которые путает ТС — это просто сериализация объекта и сериализация объекта в файл.

1) Никто лучше самого объекта не знает, как его надо сериализовать. Не даром в Java есть интерфейс Externalizable, который позволяет в самом классе объекта описать как именно нужно сериализовать и десереализовать объекты данного класса.

2) Все, что выходит за рамки непосредственно сериализации, следует вынести в отдельные классы. Например, создание XML-документа соответствующего сериализованому объекту, или JSON-запись объекта.

1) Никто лучше самого объекта не знает, как его надо сериализовать. Не даром в Java есть интерфейс Externalizable, который позволяет в самом классе объекта описать как именно нужно сериализовать и десереализовать объекты данного класса.
2) Все, что выходит за рамки непосредственно сериализации, следует вынести в отдельные классы. Например, создание XML-документа соответствующего сериализованому объекту, или JSON-запись объекта.
Иногда лучше жевать чем говорить.
Прочитайте определение сериализации. Подумайте над тем что такое XML-документ и JSON-запись. Подумайте чем имплементация интерфейса отличается от статического метода.
.
Вместо того чтобы разводить демагогию, лучше бы дали совет из реального опыта (если таковой имеется).

Пока что именно вы разводите демогогию. И что-то дельных советов от вас я тоже не видел.

И, кстати, расскажите, зачем в Java нужен интерфейс Externalizable.

Пока что именно вы разводите демогогию.
От только я вам указал на ваши ошибки, а вы просто гавкнули.
И что-то дельных советов от вас я тоже не видел.
Есть возражения против того совета который я дал, вперед в соответствующую ветку.
И, кстати, расскажите, зачем в Java нужен интерфейс Externalizable.
Ни малейшего, ни разу не видел чтобы его использовали.
Предположение: во времена JDK1.1 это казалось хорошей идеей. Если че то это где-то за несколько лет до того как начали набирать популярность технологии основные на XML и массовое осознание того что сериализация бизнес-объектов может быть больше чем в 1 формат и иметь больше чем 1 версию.

Externalizable ничего не знает о том в какой формат он сериализируется.

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

P.S. еще надо выделить сериализацию объекта в облако! :)

Вопросы дизайна сродни религиозным, но в джаве насколько я понимаю канонический способ это заимплементировать docs.oracle.com/...va/io/Externalizable.html в своем классе.

Ну или заюзать готовые сериализаторы как уже заметили.

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

Уже есть готовые маршаллеры/анмаршаллеры типа Jackson который и в XML может сериализировать. Он через рефлекшон тебе все сериализирует, соотвественно можно оставить обьект чистым. В обычном проекте ты так бы и поступил.

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

Доктор, меня учили соблюдать инкапсуляцию данных, но теперь мне очень хочется её нарушить! Что мне делать, доктор?

stackoverflow.com/...-another-object-act-on-it

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

Hint: почему именно XML, а не произвольный бинарный блоб a-la java.io.serializable?
Какую структуру там нужно воспроизводить, и зачем?
Вот эту структуру объект должен показывать наружу.

1. Чого б не використати готовий серіалізатор? Xstream, наприклад.
2. Якщо клас маленький, з невеликою областю використання, пишіть попростіше: метод статичний/не статичний більш ніж достатній.
3. Якщо сутність важлива, клас великий, використовується часто та в різних сценаріях,

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

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

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

каким боком оно противоречит сингл респонсибилити? И как вы вообще определяете респонсибилити обьекта, о котором не имеете понятия — ТС не описывал что делает и что должен делать этот класс

У меня есть класс, который содержит коллекцию объектов.

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

Когда ТС напишет о «нечтом другом» тогда и будете говорить. А до тех пор вполне логично.
Кто сказал что класс не служит для персистентного хранения этих обьектов и это его основная функция?

У меня есть класс, который содержит коллекцию объектов.
как-то противоречит этому
ТС не описывал что делает
И его респонсибилити — хранить коллекцию (состояние). Единственное что ему нужно — это интерфейс доступа к состоянию. Сериализация, или любое другое представление этого состояния — это уже совершенно другая задача и совершенно другая зона ответственности
сингл респонсибилити не, не слышал
Ну кто-то например ставит здравый смысл выше догм хомячковых идолов. Ты например когда на джаве пишешь, под каждый класс пишешь отдельный HashCodeCalculator или все таки юзаешь object.hashCode() ?

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

object.hashCode()
за меня это обычно делают фреймворки, либы и т.д. Но утрировать тоже не стоит — так можно договорится до того что нельзя конструктор в классе описывать.
Мелкие утилитарки — это разумный компромис. В то время как сериализация — задача, которая требует сервиса для её выполнения. Вот что нужно будет делать когда XML будет не нужен, а нужен JSON или вообще Raw binary, или вообще очень много форматов? Писать новые методы? Добавлять параметр формата?

Ну так в случае имплементации Externalizable там тоже получается короткий код вроде : writeLong(myField) к которому можно прикрутить любую имплементацию сериализации xоть xml, хоть json.

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

причем тут причины для изменения? Обьект не должен ничего знать ни о каких причинах по которым его изменили.

Объект и не может об этом ничего знать. Принципы SOLID предназначены для понимания человеком (программистом).

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

Single responsibility principle
Open-closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle

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

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

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

раз не указал ничего то исходим из того что написано. А вопрос он задал потому что у него нет опыта програмирования, и поэтому он задает вопрос в таком виде что на него нельзя ответить однозначно и как следствие народ начинает копипастить цитаты из вумных книг и учебников.
Посему — с чего вы взяли что сериализация не связана с напрямую с классом? Что сохраннение сериализованных данных ( ТС же пишет " класс, который содержит коллекцию объектов") не является его задачей — в данном случае сохранить эту колекцию а потом ее откуда то вынуть.

У меня тоже нет такого опыта, так что не могу говорить как «гуру». Мое ИМХО — если у ТС возникли сомнения, значит, на это были причины. Было бы, конечно, лучше узнать больше подробностей насчет того, для чего класс предназначен. Скорее всего, в нем хранится множество методов, которые обрабатывают эту коллекцию. И именно поэтому сериализация уже выходит за рамки прямой ответственности.

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

дано:

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

Сериализатор сериализует данные. «Себя» — это частный случай, если данные свои. Данные могут быть внешними — одкуда то ж взялась эта колекция внутри данного обьекта.
Возможно данный обьект и есть сериализатор. Возможно он делает что то еще. Но даже если он делает что то еще не значит что функцию сериализации следует выносить в другой классс, хотя бы потому что тогда будет противоречие с другим принципом — инкапсуляция данных.
И тогда начнеся срач какой принцип приоритетнее — принцип принцип единой ответственности или инкапсуляция — главный принцип на котором базируется собственно ООП.
Welcome в мир ПРАКТИЧЕСКОГО програмирования :)

Welcome в мир ПРАКТИЧЕСКОГО програмирования :)
спасибо. до свидания
ПРАКТИЧЕСКОГО програмирования
в мире практического программирования инкапсулированные данные обвешиваются атрибутами сериализации, а потом объект скармливается какому-нибудь XmlSerializer-у (не знаю, как он там в джаве точно называется), у коготорого два метода — записать объект в поток, и считать обратно...

А вот это

главный принцип на котором базируется собственно ООП
просто слепой догматизм...

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

Туда входит и вышеупомянутый SOLID, и GRASP, и Dependency Injection.
Целый набор принципов объектно-ориентированного дизайна...

Ух ты, не слышала раньше о GRASP) Буду разбираться, спасибо!

Спасибо, именно то, что надо.

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

Это все придумано позже — ничего из этого в книге Страуструпа вы не найдете.
И почему следование SOLID это не догматизм а следование инкапсуляции - догматизм?
Без всех вышеприведеных (и прочих новомодных) принципов ООП может существовать а без инкапсуляции — нет.

без инкапсуляции — нет
А рефлексия видимо вообще под запретом — уж большего способа нарушить инкапсуляцию нету... Вышеупомянутая сериализация в основном с ее помощью и работает.

И даже если я напишу
public class A
{
public int b = 2;
}
то мир не перевернется, и ООП никуда не денется.

Single responsibility principle

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

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

Если вы C++ разработчик — создайте метод.
Если Java-разработчик — создайте классы Serializator, SerializatorType, Deserializator и SerializatorFactory.

P.S.
I had a problem and used Java.
Now I have a ProblemFactory

правильно будет

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

Если у вас сущность жестко привязана к сущности «xml-файл», то можно и оставить в статическом методе.
Но в общем случае эффективнее сделать отдельный класс-хелпер, который занимается сериализациями. Один класс-сущность == один сериализатор — это очень тяжелое решение, а вот некоторое общее место для сериализации — вполне логичное решение.
Но в любом случае надо смотреть на конкретную задаче (на домен).

ППКС
От себя добавлю, что был период когда было мучительно больно за принятое решение кинуть маршаллинг на DTO объекты, хотя сходу оно ж кажется «таким простым и логичным», теперь период когда «мы медленно спускаемся с горы»: каждому свечку свой шесток. Если класс за что-то отвечает — пусть он за это и отвечает и совершенно по-барабаны должно быть, сериализуют его или нет и во что.

я бы в один класс это не пихал, но если без этого никак, то что поделаешь

Вопрос джуна независимо от языка исполнения.

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

Вы за отдельный класс?)

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

вы экстрасенс? как вы по топику ТСа определили какие функции у класса и как они связаны и что их целая «куча»?

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

если бы у вас был опыт вы вы не устраивали гадания. Мой опыт подсказывает что через таких умников проекты разрастаются сотнями классов «на всякий случай» половину которых можно безболезненно выкинуть. Именно то что называется индусским кодом.
не надо гадать, это не лотерея — когда ТС напишет что класс должен еще и почту слать тогда и будете высказывать свои умняки.

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

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

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

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

Зачем городить отдельный класс? Создайте метод

А не один ли хрен? Если тебе это надо (требование интерфейса) — тупо напиши метод, который вызовет эту функцию. Надеюсь ты сделал её static? Если не надо — потом напишешь когда понадобится.

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

зачем откладывать на послезавтра если можно отложить на позавчера))

Все проще. Послезавтра наступит, а позавчера уже нет ))

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