Инкапсуляция
Моё мнение следующее. Понятно, что инкапсуляция полезна для данных - каждый объект должен сам разбираться со своими данными. Но приватные методы не нужны, ибо их неудобно тестировать, они показывают недостатки дизайна. Лучше передать эти методы в какой-либо агрегированный объект.
Но и с данными должна быть некая условная инкапсуляция. То есть должен быть не полный запрет, а генерирование предупреждений компилятором (интерпретатором) в случае их использования. Такой подход может пригодиться при рефакторингах.
"Кишки" и функции, условные операторы и т.п. будут использовать только те, которые они получили из стандартного интерфейса?
koodeer, ты повторяешься. Может ты думаешь, что если повторить одно и тоже несколько раз, то я изменю своё мнение?
Аналогично и с hivewarrior. Понятно, что тебе рефакториг не нужен, что ты пишешь совершенный код. Но я так не умею - вот и выдумываю способы, чтобы используя свои скромные способности не сильно отставать от гениев.
Аналогично и с hivewarrior. Понятно, что тебе рефакториг не нужен, что ты пишешь совершенный код. Но я так не умею - вот и выдумываю способы, чтобы используя свои скромные способности не сильно отставать от гениев.
Я не пишу совершенный код. Ошибиться в 100 килостроковом приложении проще простого, но когда ты пишешь 50 разных модулей, вылизываешь их, а потом собираешь в один проект... Ошибки не исчезают, а появляются только на стыке этих 50 модулей. И уже эти проблемы ты второй раз решаешь и стыкуешь их идеально.
Ну и конечно же, после сдачи проекта, вместо записи его на болванку или в хранилище, ты удаляешь его. Мол, поддержки не ждите. Нет же. У тебя остались исходники от 50 модулей и стыковки этих модулей. При рефакторинге не обязательно же править финальный код, можно править один из 50 модулей.
Алсо, метод с публичным методом "test" ты почему-то не рассмотрел, что наводит на мысли о нежелании смотреть на альтернативные способы тестирования кода. Так же проигнорировал замечание по поводу повторного использования кода. Да и вообще, из моего сообщения вынес только то, что благодаря вылизыванию (кстати, многочасовому) кода, в моих приватных классах нет ошибок (вернее они есть, но не заметны пользователю и мне). И эту кропотливую работу с издевкой называешь "гениальностью". Это печально.
Публичный метод test - это хакерство. Можно ещё френды использовать, хитрое наследование. Про хакерство я сразу говорил.
Про повторное использование могу сказать так, что невозможно предсказать, будет ли использован какой-либо объект, но чем он проще, тем выше вероятность его использования. Вот объект "полиэтиленовый пакет из супермаркета" многие используют как пакет для мусора, например. Другие - как сырьё для плетения ковриков. Вот тебе и повторное использование. Так же и с кодом.
А ты понимаешь для чего используются локальные функции? Они порождают замыкание и зачастую их достаточно трудно вычленять из тела метода, так как приходится протаскивать через стек (либо поля) все переменные на которые замыкаются тела. Я уже не так давно говорил, что в Nemerle достаточно редко используются приватные методы - вместо них используются локальные функции.
В Python тоже есть локальные функции и я их использую. Но в большинстве случаев именно для выделения метода. Понимаю, что некоторую гибкость может дать возврат локальной функции. Но в этом случае, лучше чтобы она и охватывающая функция были достаточно малы, чтобы не запутаться.
Вот обычный пример, он выполняет типизацию грамматики.
Почему не понадобится? Если структура состоит из отдельных деталей, то увеличивается вероятность, что часть деталей может пригодится где-то ещё. Если у детали одна обязанность, то больше вероятности, что её можно использовать где-то ещё.
Хотел бы прокомментировать одну цитату двумя другими:
...каким бы тщательным ни было проектирования приложения – невозможно предугадать, что понадобится через полгода-год. Более того, попытки предугадать приведут лишь к пустой трате времени. Ибо будет реализовано очень много того, что не понадобится с большой вероятностью.
А потому – логичное решение: реализовывать то, что нужно прямо сейчас. Возможно, с небольшим заделом на будущее, можно оставить немного места для маневров, если таковые понадобятся, но только если это не займет много времени. (оригинал)
В проектировании приложения есть числа 1 и 0. Что означает, что компонент приложения либо есть, либо его нет. В случае возможного присутствия хотя бы двух одинаковых компонентов, стоит считать, что их может быть неопределенное число N и, соответственно, основывать бизнес-логику именно на этом предположении. (оригинал)
Мой вывод: только лишь ради большей вероятности возможного повторного использования такую систему строить не надо, а в целом идея разбиения на подзадачи мне понравилась. Но опять же, не в каждом случае.
Могу ещё раз повторить. Ведь ты так и не ответил внятно.
Имхо, так как ты усложняешь архитектуру приложения, вынося внутренние методы одного класса в другой, поэтому становится нужна куча лишних тестов. Оставь их в самом классе, и достаточно будет простых ассертов и т. п.
Я так понимаю, ты не рассматриваешь возможность того, что авторы SmallTalk могли просчитаться, сделав все методы открытыми?
Имхо, так как ты усложняешь архитектуру приложения, вынося внутренние методы одного класса в другой
Так там еще и названия классам надо придумывать. Иногда класс просто не нужен - достаточно одного метода с локальными функциями, где данные будут автоматически через замыкания передаваться.
Опять нет. Данные будут обрабатываться тем, у кого обязанность обрабатывать, и храниться в том, у кого обязанность хранить. Это может быть и один объект.
Если следовать принципам ООП, а конкретно - инкапсуляции, то это и ДОЛЖЕН БЫТЬ один объект.
Есть такое мнение: "Тестирование черного ящика (когда мы намеренно игнорируем реализацию) обладает рядом преимуществ. Если мы игнорируем код, мы наблюдаем иную систему ценностей: тесты сами по себе предоставляют для нас ценность. В некоторых случаях это вполне оправданный подход, однако он отличается от TDD". Кент Бек (TDD, Питер, 2003, стр 199).
Ок, не вопрос, в некоторых случаях модульные тесты могут затачиваться и на определенную реализацию, но реализацию модуля, а не нескольких и их связок.
Кстати, раз уж вспомнил Бека, то вот ещё из его заметок:
Another misleading dichotomy is between black-box and white-box tests. Since TDD tests are written before the code they are to test, they are black-box tests. However, I commonly get the inspiration for the next test from looking at the code, a hallmark of white-box testing. The advantage of black-box testing is you aren’t influenced by the code so, even if you write some redundant tests, you have a good chance of writing tests that weren’t imagined by the programmer. The advantage of white-box testing is you can use the structure of the code to identify classes of equivalent inputs and avoid wasted tests. TDD doesn’t take advantage of independent verification (although you could apply that technique on top of TDD), but it gets some of the advantages of black-box testing along with the advantages of white-box testing.
Почему не понадобится? Если структура состоит из отдельных деталей, то увеличивается вероятность, что часть деталей может пригодится где-то ещё. Если у детали одна обязанность, то больше вероятности, что её можно использовать где-то ещё.
Вероятность и необходимость - разные вещи. Вот если бы ты взял мой пример без переделки, то обнаружил бы, что либо надо было бы создать весьма специфичный вспомогательный объект, который был бы заточен под конкретную модель данных, а именно что элемент контейнера имеет поле value, либо тебе пришлось бы создавать уж очень универсальный метод, который кроме контейнера принимал бы ф-цию геттер (чтоб достать нужный элемент из контейнера) и ф-цию для проверки условия.
А если логика первоначального приватного метода была бы чуть сложнее? Например, поведение внутри цикла было бы более ветвистым. Это свело бы на нет написание универсального метода и сделает очень маловероятным повторное использование не универсального (ну часто тебе ещё где-то нужен метод, который в процессе суммирования умножает каждый второй элемент на пять, а каждый третий на два?)
Но это бонус, конечно. Основное преимущество в том, что можно протестировать методы всех классов, не нарушая инкапсуляцию крупных объектов, собранных из экземпляров этих классов.
Ну уже было ни раз сказано, что инкапсуляция их нарушается а первую очередь потому, что данные в одном месте, а код в другом.
Ок. Не буду трогать святое. Однако не вижу, почему я подогнал "нагло". Сделал код конкретным, вот и всё :)
Ты подогнал код под универсальность. Изначально он был более конкретным, а ты его сделал более общим.
"Десяток приватных членов класса" обычно показывает, что класс неприлично разросся. Особенно, если все их надо использовать в одном приватном методе. В большинстве случаев их можно сгруппировать.
Я утрировал с десятком, с другой стороны не обязательно же должны быть данные, это могут быть и специфичные методы, которые в твоем случае видимо должны будут быть представлены колбеками, функторами или чем-то ещё.
А в чём тут преимущество скрытого метода? В том, что его можно не проверять? Авось сработает?
А при чем тут скрытый метод? Вся фишка в том, что изменение реализации никак не отразится на тестах. А скрытый это метод или нет - не имеет значения.
И здесь приходим к ещё одному выводу: слова "приватный" и "паблик" не имеют отношения к реализации. Реализация всегда приватная. Поэтому тестирование приватных и неприватных методов - это весьма условное деление.
Вот поэтому я всю тему и объясняю каждому, что речь не о вложенных классах. Понятия не имею почему некоторые думают, что агрегированный объект - это вложенный класс.
Честно говоря, в контексте обсуждения не вижу между ними разницы.
Протестировать всё невозможно - об этом у Макконнелла доказывается. Поэтому есть вероятность того, что при прохождении всех тестов интерфейса останутся ошибки, которые будут выявлены при использовании программы. Как найти код, который вызывает эти ошибки? Может у тебя на выходе то, что требуется, а внутренний код вызывает какой-нибудь левый разрушительный метод? Думаю, тут поможет возможность потестировать "кишки".
А модульное тестирование не предназначено для локализации ошибки внутри модуля, а для ответа есть ошибка или нет.
Кроме того, подход "чёрного ящика" противоречит классическому TDD (смотри цитату, смотри книгу). Но можно конечно использовать и другую систему.
Да нет такого понятия "классическое TDD", кроме того "черный ящик" ничему не противоречит, см. цитату в моем посте.
Он еретик и раскольник. :) "Шучу" (с) Когром.
Почему объектно-ориентированное программирование провалилось?
Гоу все в процедурщину! Там нет открытых-закрытых методов.
Это условное разделение, я думаю. Поэтому не смогу чётко ответить.
Ну почему же раскольник? Наоборот, я сплотил коллектив :)
Вообще, тут много аргументов было, которые мне надо не спеша обдумать. Например, некоторые вопросы от hardcase созвучны предположению, высказанному в книжке Кента Бека , что TDD нельзя использовать для разработки интерпретатора (компилятора) языка программирования.
Или вот такие фразы:
Однако, я предполагаю, что инкапсуляция - это принцип модульного программирования, а в ООП оно косвенно получается на основе таких принципов:
- Объекты могут обладать состоянием.
- Посылка сообщения - единственный способ обмена информацией между объектами.
Цитата отсюда:
http://www.smalltalk.ru/articles/smalltalk.html
Если так рассуждать, то и остальные "принципы ООП" (полиморфизм, наследование) - необязательные для ООП, но могут в нём присутствовать.
Но это не утверждение, а некая справка.
Напомнило Дугласа Адамса, "Ресторан <У конца Вселенной>"".
Как там было?
- Но вы хоть уверены, что вот этот вот кот, которого вы гладите, существует?
- Отнюдь. Мне просто приятно вести себя таким образом по отношению к тому (или чему?), что представляется мне котом. Я не имею никакого представления о его подлинной сущности.
#include <header.h>
#undef private // А вот пока анонимус не дописал undef это и было грязным хаком.
...
Header *h = new Header();
int x = h->m_value; // m_value в прошлой жизни - private
К стати, подобное наверное можно применять в оболочках которые будут тестировать модули, в результате в тестах будет все открыто для тестирования, а в релизах уже будет полная инкапсуляция.
К стати, подобное наверное можно применять в оболочках которые будут тестировать модули, в результате в тестах будет все открыто для тестирования, а в релизах уже будет полная инкапсуляция.
Это прям как дефолт-сити. Ведь не все языки поддерживают шаблоны. =)
А где ты шаблоны тут увидел? о_О
Я с плюсами то незнаком, звиняйте, если ошибся.
Жорж, ты меня печалишь... плюсы ж они как английский язык, говорить на нем не обязательно, но ориентироваться надо.
Ты мыслишь шаблонно. Кто такие плюсы, чтобы они были как английский язык? :)
И потом ориентироваться - это не значит знать точную терминологию, что делает эта директива прекомпилятора я знаю. ;)
Ага, а ещё C, C# и Java.:) Где там был соседний тред про языки?
Целесообразность компромиссов я рассматриваю, но мне надо знать между чем и чем компромисс. Бесконечное разделение классов до элементарных объектов - это одна сторона, сокрытие методов - другая. Сокрытие методов с помощью интерфейса (или абстрактного класса) - одна сторона, сокрытие методов с помощью модификаторов доступа - другая.
Вот эти крайности я и выделял.
Понятно, что выделение класса требует больше усилий, чем использование модификатора доступа. И при недостатке времени их удобно использовать. Но полагаю, что основное назначение этих модификаторов - показать, что методы не предназначены для внешнего использования (типа, пусть будет так, ибо некогда рефакторить класс). Но не вижу смысла в том, что эти методы блокируются для внешнего использования. Ответственность за использование лежит на том, кто использует. Автор лишь должен ему оставить некий знак. Короче, это уже философия Python :)
Ну не методы, а функции и переменные есть закрытые. Есть они в паскалевских модулях (те, что не вошли в интерфейсную секцию). А в си есть static.
Хватит теории! Kogrom, даёшь продукты!
//слез с броневика
Один всем нам известный УК взял вот, и, не зная ни слова на РНР, сделал таки два дивных веб-сервиса, которые пусть и не уникальны, но по-своему хороши, и лично у меня вызывают массу приятных эмоций своей простотой и практичностью. Мне повезло меньше: я, не зная ни слова на VB.NET, вопреки и через попу выпустил для фирмы продукт, позже превращённый в заготовку, которой фирма до сих пор пользуется. Так вот, ни у кого из нас потом не спрашивали, что такое инкапсуляция! Интересно было совсем другое, и в первую очередь - что ты уже сделал.
И потом ориентироваться - это не значит знать точную терминологию, что делает эта директива прекомпилятора я знаю. ;)
Не так ставишь вопрос ты. Кто такие эти англичане, чтобы их язык был как плюсы?!:rolleyes:
Можешь создать про различие этих понятий отдельную тему, если хочешь. Но эта тема именно про инкапсуляцию. И я наивно полагаю, что не на пустом месте возникло более ста сообщений.
Просто интересных тем по делу мало чет в последнее время бывает, а попи*деть охота. ;)
Поэтому не могу не согласиться с Sanila San'ом о том, что лучше уж выпускать так или иначе работающие продукты, чем про инкапсуляцию трындеть, и с Оксотником (прощаю) в том, что тут трындят ради потрындеть, а не ради создания новых технологий и подходов в программировании.
Выгнал, да?:D
Я вообще о другом: мне плевать на то, как что называется. Мне более интересно, что в конечном итоге выходит. Потому что можно до посинения определять значение терминов или способы правильной инкапсуляции, а можно делать что-то, чем потом можно пользоваться.
Я тебя просто попросил не разводить оффтоп. По хорошему, тему можно разделить на две с твоего сообщения "даёшь продукты". Новой теме дать название "теория и практика" или что-то типа того.
А как ты думаешь, чем я зарабатываю? Я даже в какой-то из соседних тем писал об этом. Но с какой стати мне выкладывать в Internet то, над чем я работаю, чтобы ты оценивал можно пользоваться или нет? Это не совсем моя собственность.
Ради юмора могу привести ссылки на программы, которые я делал, когда не был программистом. Например, вот тут целый "театр":
http://kogrom.narod.ru/progr/flash/flash.htm
или вот игруха:
http://kogrom.narod.ru/progr/flash/wolfsf.htm
Это поделия ещё те, но они уже в каком-то смысле являются программами, ими пользовались. Но программными продуктами они не являются по определённым признакам. Чтобы понять по каким - читай "Мифический человеко-месяц".
Чрезмерное теоретизирование без практики никуда не годится. Как и практика без теории порождает продукты плохого качества. Баланс надо соблюдать. А то тут куча постов, а практический их толк в чем? Я вот все равно буду использовать приватные методы. Потому что мне так удобно. Потому что я так научен. Потому что я ничего лучше не придумал пока.
Ой, только без фанатизма. Я давно уже сторонник практического подхода и углубленного изучения вопроса только когда действительно прижало. Если тебя и правда прижало, то я лучше воздержусь от дискуссий и понаблюдаю с попкорном. В битву гигантов, таких как ты, Green, oxotnik333 и hardcase, мне даже встревать боязно. Чесслово, я ведь уже не программирую некоторое время, я больше по управлению сейчас. Ну это к делу не относится.
Брукса прочитал не раз и не два, различия между продуктами и всем остальным знаю. Я вообще больше о том, что не техникой единой: Цукерберг крут тем, что написал фейсбук; Брин со товарищи круты гуглом, круты авторы gcc, vim и особенно круты те, кто реверсил OS360 под ЕС ЭВМ. Я не скажу, что крут: моим поделием после рефакторинга пользуется местечковая алматинская фирма, и всё же: если бы я рассуждал о программировании вместо того, чтобы писать хоть как-нибудь, ничего этого не было бы. Хотя таки да, если не обсуждать профессиональные темы, роста не будет. Другой вопрос, не зашло ли обсуждение в тупик? Не мне решать.:)
Знали ли Пушкин, Бунин или Пелевин, что такое деепричастный оборот и сложносочинённое предложение?
Широко известная в узких кругах модель обучения ;)
Итак, вы начали учиться водить машину. Вскоре вы обнаруживаете свои ограничения. Вы выполняете задания инструктора и сознательно следите за всеми рычагами, рулем управления, координируете нажатие на педаль сцепления и слежение за дорогой. Это захватывает все ваше внимание, вы еще некомпетентны и придерживаетесь улиц с неоживленным движением. Это стадия осознанного незнания (некомпетентности), когда вы разламываете шестеренки коробки передач, виляете из стороны в сторону и наводите ужас на
велосипедистов. И хотя эта стадия является беспокойной (в особенности для велосипедистов), именно в это время вы усваиваете большую часть необходимого.
Это приводит вас на стадию осознанного знания (компетентности). Вы можете управлять машиной, но вы концентрируете на этом все свое внимание. Вы освоили умение, но еще не овладели мастерством.
И, наконец, целью ваших усилий является неосознанное знание. Все те отдельные навыки, которые вы с таким усердием осваивали, плавно сливаются в одно целое. Теперь во время вождения вы можете слушать радио, наслаждаться пейзажем. поддерживать беседу. Ваше сознание определило цель и предоставило возможность подсознанию выполнять поставленную задачу, освободив ваше внимание для других целей.
да. Правда на счет Пелевина - не уверен. :)