LINUX.ORG.RU

Структура vs класс


0

0

Часто замечаю вот такое. Вместо

struct Name { int param1; int param2; }

используют класс с доступом к переменным через функции (set, get). В той же Qt я вообще ни разу не видел «прямой» доступ к переменным. Чем это объясняется? Почему использование функций предпочтительнее? Всё таки количества кода во втором случае явно больше.

Ответ на: комментарий от jtootf

>тем, кто пишет такой код, куда полезней грамотно проектировать интерфейсы ;)

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

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

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

равно как и геттеров/сеттеров

jtootf ★★★★★
()
Ответ на: комментарий от KRoN73

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

просто не обращайте внимание на это быдло

lester ★★★★
()
Ответ на: комментарий от KRoN73

> Боюсь, что ты сейчас споришь только о вопросе трактовки термина.

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

lester ★★★★
()
Ответ на: комментарий от eugine_kosenko

>Женщина — это Барбара Лисков?

Вот не помню уже напрочь, а книжку лет 15 тому назад потерял :) Но именно по ней я понял, наконец, что ООП - это не что-то страшное и непонятное, а, грубо говоря, «структуры данных с методами» :) Страуструп тогда (особенно учитывая, что всё изучалось в теории, Си++ компилятора не было тогда у меня) казался непонятным.

А вообще в то время все учились по Бучу и Шлаеру-Меллору.


Или не попадались мне, или уже забыл таких.

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

Боюсь, что ты сейчас споришь только о вопросе трактовки термина.

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

стек, который выдёт наружу поле .data, имеющее интерфейс вектора,- плохой стек. стек, который не имеет никакого другого интерфейса, кроме как <геттера/сеттера> поля .data - очень плохой стек. пример утрированный, однако мысль, я надеюсь, доносит

в случае же, если непосредственный доступ к абстрагируемым данным всё же необходим (как в случае с точкой), использование геттеров любого вида смысла не имеет. контроль за обработкой данных - задача других сущностей, value type должен быть value type'ом

jtootf ★★★★★
()
Ответ на: комментарий от anonymous

Да, и вообще он виноват в том, что родился не в то время и не в том месте.

eugine_kosenko ★★★
()
Ответ на: комментарий от jtootf

>возможно, хотя вряд ли

Ну, давай для уточнения вернёмся к моему примеру :)

Пусть у нас есть объект, имеющий поле страны. В базовом варианте параметр - это переменная, загружаемая с помощью ORM из БД. Поскольку (как тут ратовали за Worse is better) нужно делать систему уже сейчас, а не завтра, сегодня эта переменная вписывается в БД как есть, строкой, но завтра - потребуется расширение до фиксированного списка и хранения не строки, а идентификатора.

Если мы напишем вариант с прямым доступом к переменной класса так:
some_func(our_object->country_name),
то завтра, вводя функцию вида:
func country_name() { return (new country(this->country_id())->title()); }
нам придётся и переписывать всё использование на
some_func(our_object->country_name()),
Не проще ли сразу написать:
func country_name() { return this->country_name; }
и в будущем не иметь геморроя с интерфейсом объекта?

Это - геттер или нет? :)

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

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

Не проще ли сразу написать

проще. но хуже

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

Это - геттер или нет?

геттер. и он мне несимпатичен

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> по-настоящему скрывал бы внутреннее устройство объекта

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

lester ★★★★
()
Ответ на: комментарий от KRoN73

То есть, когда тебе через полгода придётся вводить проверку или менять внутреннее представление, ты будешь переписывать весь использующий данный объект код? Нет уж, я лучше геттер/сеттер организую :)

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

Legioner ★★★★★
()
Ответ на: комментарий от KRoN73

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

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

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

anonymous
()
Ответ на: комментарий от tailgunner

>

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

golodranez ★★★★
()
Ответ на: комментарий от tailgunner

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

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

golodranez ★★★★
()
Ответ на: комментарий от golodranez

> переписывать пол программы?

вы «немного» преувеличиваете

lester ★★★★
()
Ответ на: комментарий от jtootf

>геттеры ничем существенным не отличаются от прямого досутпа к данным. и никакой инкапсуляцией тут и не пахнет

перечитай ещё раз.

а разделение интерфейса и реализации

не разделение, а сокрытие реализации и _данных_

golodranez ★★★★
()
Ответ на: комментарий от jtootf

>равно как и геттеров/сеттеров

Тебе название не нравится чтоли? :))

golodranez ★★★★
()
Ответ на: комментарий от thesame

>Так и будем писать код «а если вдруг»?

Это гораздо лучше чем писать «и так покатит»:)) и любому программисту при продумывание архитектуры вот это «а если вдруг?» надо всегда держать в уме.

golodranez ★★★★
()
Ответ на: комментарий от golodranez

> KRoN73 ведь приводил пример, что ему нужно было получать данные из базы.

Ты не можешь учесть всё. Просто пойми это, смирись и не загромождай программу кодом, который не нужен.

Как это сдулать с прямым доступом?

Читать объекты из БД и записывать их туда же?

переписывать пол программы?

Ахренеть. Да что там «переписывать» - [гс]еттеры добавить? Да, это не каждый сумеет.

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

tailgunner ★★★★★
()
Ответ на: комментарий от golodranez

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

thesame ★★★★
()
Ответ на: комментарий от jtootf

> кто мешает поставить breakpoint на изменение самой переменной (области памяти)? и gdb, и оффтопичный отладчик такое давно умеют

Это watchpoint называется. Во-первых, не на всех архитектурах есть аппаратная поддержка, а без неё это ужасно тормозит (ужасно — это действительно ужасно, хуже жабы 8)) ), во-вторых, watchpoint тебе придётся ставить для каждого экземпляра класса/структуры отдельно, а breakpoint на метод ты можешь поставить один раз для всех. Наверное, иногда это действительно нужно...

kemm
()
Ответ на: комментарий от kemm

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

ratatosk
()
Ответ на: комментарий от golodranez

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

О, да! Это действительно, без шуток, прекрасный пример современного проектирования и прогрммирования (сюда же и «рефакторинг» в виде пункта меню модных IDE относится).

Т.е. было у нас что? Было у нас «получить из класса значение приватного поля. Моментально, и это значение всегда есть». А стало у нас что? А стало у нас «получить значение какого-то поля из какой-то таблицы в какой-то базе данных, которая неизвестно где находится. ХЗ за сколько времени выполнится запрос, ХЗ есть ли подходящие под условия данные в базе, ХЗ не отвалится ли база на полпути, etc.» Даже если все эти проверки понапихать в геттер, всё равно фигня получится. Всё равно надо проверять каждое использование геттера глазами. Всё равно где-то вылезет требование меньших задержек, чем зашит таймаут в геттер, и так далее, и тому подобное.

Где обещаный profit? В том, что R лет все мучались с геттерами, чтобы потом всё равно всё переписывать? Да уж, PROFIT...

kemm
()
Ответ на: комментарий от naryl

А в D2 обращение к полю можно заменить на свойство без нарушения сорцовой совместимости.

А в D1 - на метод с таким же именем.

На С++ тоже можно, на шаблонах такое налабать

yoghurt ★★★★★
()
Ответ на: комментарий от jtootf

>вместо этого можно было бы написать что-то вроде our_object.getReport()

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

KRoN73 ★★★★★
()
Ответ на: комментарий от eugine_kosenko

>А завтра мы просто заменим переменную на свойство :-)

Это хорошо, когда язык такое позволяет :)

KRoN73 ★★★★★
()
Ответ на: комментарий от eugine_kosenko

>Кстати, по Смоллтоку и Симуле книги тоже были.

По Симуле - не видел. По Смолтоку было что-то, помню, но совершенно ни для чего непригодное. Теории полезной никакой, а практики - и подавно :) Какой Смолток на практике на PC в 1992-м? :)

KRoN73 ★★★★★
()
Ответ на: комментарий от Daeloce

В Smalltalk написание сигналов аксессоров (геттеров) и мутаторов (сеттеров) есть единственный способ предоставить доступ к переменным объекта/класса.

yoghurt ★★★★★
()
Ответ на: комментарий от Legioner

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

Да.

Вместо конструкторов фабрики


Э... Фабрика объектов у меня итак есть. Каким образом она поможет в нашей ситуации?

вместо маленького свитча развесистая иерархия, и всё это в 100% случаях?


Какой свитч? Ты о чём?

KRoN73 ★★★★★
()
Ответ на: комментарий от golodranez

Макконел - Капитан Очевидность #1. Не понимаю, почему от него так писаютъ кипяткомъ

yoghurt ★★★★★
()
Ответ на: комментарий от thesame

>А если вдруг нет? Так и будем писать код «а если вдруг»?

У меня ситуация немного проще. Ибо не Си, а PHP. Мне не нужно писать обёртки. Поэтому код геттеров/сеттеров я не пишу, методы имитируются. Аналогично можно сделать в Питоне, скажем. А в Руби - и не нужно, там уже нормальные свойства.

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

Кроме того, экономия от появления ситуаций «а вдруг» в моей практике, всё же, превосходит затраты на написание лишних обёрток.

Новые классы создаются не так уж часто, можно применить, например, кодогенератор, если совсем уже копипастить влом. Так что затраты - небольшие. Зато позволят сэкономить уйму времени, если завтра придётся переписывать структуру объекта.

KRoN73 ★★★★★
()
Ответ на: комментарий от tailgunner

>Ты не можешь учесть всё.

Это не повод забивать вообще на расширяемость.

Если усложнение программы на 20% решит 80% будущих проблем - это уже повод браться за усложнение, а не плакать, что оно никому не надо, раз 100% не перекрывает :)

Читать объекты из БД и записывать их туда же?


ORM, кстати, тоже по хорошему должна работать с любым видом объектов. И потому - с достаточно унифицированным.

Ахренеть. Да что там «переписывать» - [гс]еттеры добавить?


Соционика детектирует запущенный случай деловой логики :)

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


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

Если требования изменились круто - переписывать.


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

...

А вот когда не заботился об инкапсуляции - переписывать приходилось что-нибудь капитально каждые полгода. И до сих пор иногда доводится переделывать старый код. Сейчас процентов 80% всей нагрузки - это переписывания старого, «доинкапсуляционного» кода 3-6-летней давности :) Когда приходится что-то переделывать в коде с геттерами/сеттерами, всё решается во много раз проще.

KRoN73 ★★★★★
()
Ответ на: комментарий от thesame

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

Ну, это слишком очевидно :)

KRoN73 ★★★★★
()
Ответ на: комментарий от kemm

>ХЗ за сколько времени выполнится запрос, ХЗ есть ли подходящие под условия данные в базе, ХЗ не отвалится ли база на полпути, etc

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

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

Где обещаный profit? В том, что R лет все мучались с геттерами, чтобы потом всё равно всё переписывать?


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

KRoN73 ★★★★★
()
Ответ на: комментарий от yoghurt

>Если всё перевести на геттеры, можно сделать lazy initialization.

Да, у меня это во многих местах используется.

KRoN73 ★★★★★
()
Ответ на: комментарий от tailgunner

>>> Да не нужны никому хорошие языки! Нужны хорошие библиотеки, хорошие програмы, хорошее сообщество, хорошая документация. А языки всё равно все одинаковые.

Очевидно, хорошие языки никому не нужны по другой причине.


Если тебе это очевидно - поведай и нам


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


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

naryl ★★★★★
()

\трололо{Пишите на snit для tcl, там поля вообще наружу не могут быть доступны. Проблема решена.}

naryl ★★★★★
()
Ответ на: комментарий от KRoN73

> Ты явно уже пытаешься придраться ну хоть к чему-нибудь.

Ну не знаю. Внезапная замена O(1) метода на O(хз) у меня, к примеру, вызывает неприятие. Впрочем, в вебе это не так критично.

Shimuuar
()
Ответ на: комментарий от Shimuuar

>Внезапная замена O(1) метода на O(хз) у меня, к примеру, вызывает неприятие

Задача всё равно неизбежная. Так что вопрос к геттерам/сеттерам отношения не имеет.

KRoN73 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.