Инкапсуляция
Моё мнение следующее. Понятно, что инкапсуляция полезна для данных - каждый объект должен сам разбираться со своими данными. Но приватные методы не нужны, ибо их неудобно тестировать, они показывают недостатки дизайна. Лучше передать эти методы в какой-либо агрегированный объект.
Но и с данными должна быть некая условная инкапсуляция. То есть должен быть не полный запрет, а генерирование предупреждений компилятором (интерпретатором) в случае их использования. Такой подход может пригодиться при рефакторингах.
Моё мнение следующее. Понятно, что инкапсуляция полезна для данных - каждый объект должен сам разбираться со своими данными. Но приватные методы не нужны, ибо их неудобно тестировать, они показывают недостатки дизайна. Лучше передать эти методы в какой-либо агрегированный объект.
Но и с данными должна быть некая условная инкапсуляция. То есть должен быть не полный запрет, а генерирование предупреждений компилятором (интерпретатором) в случае их использования. Такой подход может пригодиться при рефакторингах.
Приватные матоды себя не оправдывают только в том случаи, если разработка идет в тесном коллективе не более 3х человек. Иначе любой индус, не до конца понимая всего божественного замысла создателя класса, начинает писать молитвы Шиве на языке программирования, что частенько приводит к интересным ошибкам. Так что приватные методы/данные очень даже помогают в разработке больших комплексов (а при разработке маленьких комплексов я считаю и ООП излишнем, но уже что-либо поделать поздно...)
На счет тестирования. Что мешает отладить приват метод, как паблик, а уже потом думать, чем же он будет в конце концов? Никто же не заставляет программиста сразу писать оптимальный код. Люблю сначала сделать так, чтобы работало, а потом уже улучшать, ускорять, защищать...
Как часто приходилось писать сначала отдельный модуль, отладить его в консоле, а уже потом его использовать? Так почему же нельзя этот подход и применять здесь?
Неполный запрет убьет всю суть защиты внутренностей класса. Как часто программист смотрит на предупреждения компилятором? Я только через раз, да и то на половину плюю, ибо знаю, код там вполне рабочий и каждый миллиметр там вылизан, как у кота яйца. Просто принимаю предупреждения к сведению и если они весомы, то тогда уже и исправляю.
Как-то так:rolleyes:
Какие молитвы? Приватных методов не должно быть не потому, что они должны стать открытыми. Их вообще не должно быть в конкретном классе.
А как же unit-тесты? Они же выполняются пока жива программа.
Профессиональный программист - всегда, когда они появляются. Но это отдельная тема.
Попробуй обойтись без приватного метода, в классе стека, который будет производить противоестественные данные с указателями на предыдущий элемент. Или, например, функция, которая возвращает код, который используется для защиты конфиденциальных данных. Как быть тогда?
Шаловливые ручки индусов частенько пытаются сделать очень интересные вещи с результатами функций, которые возвращают указатели на объекты, которые трогать не их ума дело. А трогать надо по логике, но не им. Вот и приходят приват методы.
Или я тебя не так понял? На что тогда предлагаешь заменять приват методы? Альтернатива защиты критичных данных?
А как же unit-тесты? Они же выполняются пока жива программа.
Что мешает проводить юнит-тесты для модулей, пока они паблик. Потом, когда передаешь их заказчику, закрываешь критичные методы/данные в приват. Тестируешь еще раз, на то, не переусердствовал ли ты. Все.
Профессиональный программист - всегда, когда они появляются. Но это отдельная тема.
{
int a=1;
if(a>1)
return 0;
else if(a=<1)
return 1;
}
В MS C++ 6.0 выдаст предупреждение, что не все пути возврата функции предусмотрены. Но мы то видим, что это не так. Предупреждение есть. Взглянуть взглянул, ну а толку?
Создаем ещё один класс для внутреннего объекта, в который перенесём все эти методы. Вместо обращений к приватным методам будет обращаться к открытым методам приватного объекта. Оно и по распределению обязанностей выйдет вернее. Я же написал об этом сразу.
Мешает их смысл.
{
int a=1;
if(a>1)
return 0;
else if(a=<1)
return 1;
}
В MS C++ 6.0 выдаст предупреждение, что не все пути возврата функции предусмотрены. Но мы то видим, что это не так. Предупреждение есть. Взглянуть взглянул, ну а толку?
Толк есть. По смыслу тут надо что-то такое:
{
int a=1;
if(a>1)
return 0;
else
return 1;
}
Великие отцы программирования ещё в прошлые десятилетия спорили на тему инкапсуляции. Были те кто говорили, что она не нужна. Но по прошествии времени все изменили своё мнение.
Будь моя воля, я бы закрывал всё и вся!
Например в C# мне сильно не хватает статических переменных методов (то, что есть в C и C++). То есть нужна такая переменная внутри метода, которая сохраняет своё значение между вызовами этого метода. Почему из шарпа это убрали - не представляю. Приходится юзать поля класса для этой цели.
Помнится, не так давно в одной теме ты говорил, что вложенные классы не нужны. Якобы это усложняет код. А теперь, в попытке избавиться от приватных методов, оказались нужны? :)
Насчёт предупреждений компилятора. Да, конечно, профессиональный программист на них смотрит, и добивается их отсутствия. Но таковых меньшинство. Всегда было и будет большинство начинающих программеров, а отсюда - быдлокод. Поэтому лучше не полагаться на разум человека, а добавить строгости в язык/компилятор/IDE.
Но приватные методы не нужны, ибо их неудобно тестировать, они показывают недостатки дизайна. Лучше передать эти методы в какой-либо агрегированный объект.
О каких тестах идет речь? В чем неудобство?
Но и с данными должна быть некая условная инкапсуляция. То есть должен быть не полный запрет, а генерирование предупреждений компилятором (интерпретатором) в случае их использования. Такой подход может пригодиться при рефакторингах.
Данные не обязательно должны быть сокрыты, но обычно при изменении некоего члена, должны вызываться какие либо внутренние механизмы, поэтому если тупо открытому члену присвоить значение, то вся идеология объекта может пойти прахом, в результате, при разработке, сам член скрывается, а для его измения используют интерфейсы в виде ф-ций-членов, в которых после изменения значения реализуется логика реакции объекта на это изменение.
Хорошо. Рассмотрим пример, когда ты изобрел новый метод супершифрования с умопомрачительной сложностью брутфорса. Но используешь для этого внутри функции, которые при показе пользователю названия или еще каких-то косвенных признаков упростят это шифрование в миллиарды раз. Как быть?
Создавать объекты для этого? То какого типа и какие? Это все равно, что вместо массива указателей на функции использовать извращения с классами. Можно - можно, но как-то противоестественно.
Мешает их смысл.
Это ты неправильно подходишь к задаче просто.
Мой подход:
1) Создаем класс с интерфейсами
2) Отладка с помощью юнит-тестов
3) Защита "от дурака" с помощью приват методов
4) Отладка с помощью юнит-тестов
Всегда работать легче, разбив задачу на много подзадач. В данном случаи подзадач две. "Создать рабочий класс" и "Создать защиту от дураков". Для каждой задачи свои юнит-тесты, во многом дублирующие друг друга, но тем проще - не надо изобретать новые.
Толк есть. По смыслу тут надо что-то такое:
{
int a=1;
if(a>1)
return 0;
else
return 1;
}
А если между ифом и элсем две тысячи строк? Так уж эта замена очевидна и помогает пониманию? С точки зрения ассемблерного кода выигрыша мы почти все равно не получаем, но теряем смысловую нить иногда. Так что предупреждения иногда ни на что не влияют.
И есть иногда в Builder XE странные предупреждения, что переменная не используется, хотя она во всю работает во внутренней логике. Как жить? Предупреждения компилятора частенько надуманы и не несут смысла, так как код писал человек он часто трудно формализуем и, соответственно, нечитаем для машины. Поэтому она и генерирует предупреждения.
Смотреть на них стоит, но не все они должны восприниматься всерьез.
Например в C# мне сильно не хватает статических переменных методов (то, что есть в C и C++). То есть нужна такая переменная внутри метода, которая сохраняет своё значение между вызовами этого метода. Почему из шарпа это убрали - не представляю. Приходится юзать поля класса для этой цели.
ИМХО логичнее использовать поле класса, нежели плодить статические переменные, в которых потом запутаться легко будет.
Насчёт предупреждений компилятора. Да, конечно, профессиональный программист на них смотрит, и добивается их отсутствия. Но таковых меньшинство. Всегда было и будет большинство начинающих программеров, а отсюда - быдлокод. Поэтому лучше не полагаться на разум человека, а добавить строгости в язык/компилятор/IDE.
Очень часто на форумах от новичков всплывает вопрос типа "мне компилятор выдал ворнинг", на что местные гуру отвечают "забей на варнинги, все ок у тебя". Так что у самих новичков интерес к ворнингам довольно таки большой, но недопрограммисты их отучают от этого интереса.
Я говорю не про вложенный класс, а про агрегированный объект. Класс будет обычным.
То есть надо равняться на отстающих?
http://ru.wikipedia.org/wiki/Модульное_тестирование
Должны быть. И ты далее объясняешь почему. Я же говорю, что для удобства рефакторинга компилятор должен позволять к ним временно обращаться, надоедая предупреждениями. Хотя, может это и не нужно. Можно их открывать руками на время, но тут можно что-то забыть.
Безусловно. Но я бы тебе рекомендовал всё же поближе ознакомиться что такое регрессионное тестирование, прежде чем такое утверждать. Не горячись, выдержи паузу :)
При чём тут ассемблер? Оно непонятно человеку, читающему код, тем более если между ними много строк. Он должен рассчитывать, что третьей ситуации не будет. Разве не лучше, чтобы автор кода об этом сразу написал.
Т.к. я далек от этого, обычно дебагером тестирую, то понимаю этот процесс как, класс - черный ящик с входом и выходом, на вход подаем все мыслимые параметры, с выхода принимаем, то как он их обработал, какую здесь пользу сокрытие принесет не представляю.
Должны быть. И ты далее объясняешь почему. Я же говорю, что для удобства рефакторинга компилятор должен позволять к ним временно обращаться, надоедая предупреждениями. Хотя, может это и не нужно. Можно их открывать руками на время, но тут можно что-то забыть.
Скрывать или не скрывать зависит исключительно от логики, и компилятор тут ни при чем - логикой человек занимается, не компилятора это дело в логику лазить.
к примеру
{
int value;
void printValue()
{
cout<<value;
}
};
int main()
{
ComeClass obj;
obj.value = 10;
obj.printValue();
return 0;
}
без инкапсуляции код сократился минимум на 3 строки, с ней надо было бы делать сеттер для ComeClass::value
{
int value;
void printValue()
{
cout<<value;
}
};
int main()
{
ComeClass obj;
obj.value = 10;
obj.printValue();
return 0;
}
без инкапсуляции код сократился минимум на 3 строки, с ней надо было бы делать сеттер для SomeClass::value
Возможно, мой вопрос покажется странным, но... Какое назначение у SomeClass? Если смысла нет, то пример неудачен.
Хорошо. Как приватные методы мешают тестированию? Их всегда можно переобъявить как паблик, а потом тестировать до посинения, но учитывать, что они в будущем станут приватными. Потом после исправления ошибки снова использовать как приват.
После переобъявления их как приват проводим еще пару тестов (а скорее всего их проведет сам компилятор, который заругается там, где нужно).
При чём тут ассемблер? Оно непонятно человеку, читающему код, тем более если между ними много строк. Он должен рассчитывать, что третьей ситуации не будет. Разве не лучше, чтобы автор кода об этом сразу написал.
Ассемблерный код, как эквивалент быстродействию.
А на счет понятности, то дело вкуса.
Это банальный пример предупреждения, которое на качество кода имеет посредственное влияние, но тем не менее присутствует. Я же не кричу: "Я пишу так, и все пишите!" Это пример предупреждения, которое воспринимать можно философски, не исправляя его, проблем оно не принесет.
Были у меня и более интересные предупреждения, которые просто непонятно как были получены IDE. Код верный, но предупреждение стоит. Я их на листочек не записывал.
Предупреждения должны беспрекословно устранятся только в ассемблере (но их там нет, лол), остальные языки предупреждения генерируют не всегда верно. Повторюсь, смотреть на них стоит, но исправлять или нет - дело программиста.
Не всегда отсутствие варнингов или их присутствие говорит о быдлокоде. Да и ужесточение IDE в плане ошибок тоже достаточно сомнительная перспектива. Алгоритмы генерируемые человеком частенько сложно формализуемы, а значит компилятору понять ошибка это или финт ушами не дано.
Лучше полагаться на то, что человек без разума не полезет не в свое \, а будет мести улицы или лить сталь.
После переобъявления их как приват проводим еще пару тестов (а скорее всего их проведет сам компилятор, который заругается там, где нужно).
Ты не выдержал паузы. Я разочарован. Эх...
Для чего нужны юнит-тесты?
Когда заказчик в очередной раз попросит меня внести изменения в программу, когда я их внесу, то вот эти самые тесты запущу, чтобы убедиться, что не внёс ошибок своими правками. Это только половина их назначения. Вторая половина - создавать гибкую ООПшную структуру кода.
А ты предлагаешь мне во-первых помнить какие методы были приватными для 500 классов, править их при каждом чихе заказчика, во вторых, ты предлагаешь отказаться от второго назначения юнит-тестов.
Хмм, на мой взгляд, легче запутаться в лишних полях класса. Это поле можно случайно изменить в другом методе, это поле видно в списке членов класса (хотя оно там не нужно), etc.
Подумал. Да, учту это, и впредь постараюсь сам подобного не советовать.
Нет. Думать о будущем.
Если большинство программистов - начинающие, то почему бы не предусмотреть способ, как избежать элементарных ошибок? И сделать это должны как раз опытные программеры - те, кто пишут компиляторы.
Ладно, буду молчать.
А нет, кое что скажу:
УК, если есть чоткая структура программы, то правка не представится таким уж большим делом.
и это, про пиццот классов - это же умом тронутся. это что, новый фреймворк какой-то или просто сказали?
Вот именно - чёрный ящик. То есть всё внутренние члены должны быть private. А если что-то выставить наружу, как public, то сторонние разработчики могут это использовать. А потом изменишь свой класс - и перестанет работать код у тех разработчиков. Стало быть - сокрытие нужно. Оно для того и придумано.
И статическая переменная внутри метода служит той же цели - метод становится настоящим чёрным ящиком. А поле класса вместо этого - приоткрывает этот ящик.
Стандартный способ:
- отключаем предупреждение; pragma и т. п.
- финт ушами;
- включаем предупреждение.
Но предупреждение должно быть, если не отключено самим человеком!
Когда в сильные снегопады (а живу я на севере и снега здесь дохрена) я хожу помогать убирать снег знакомой женщине-дворничихе (мне всё равно - что снег кидать, что гантели тягать, а ей - облегчение), то оказывается, что мозги нужны даже для этого. Я мог бы целую лекцию по уборке снега прочитать, ну да ладно...
Насчёт литья стали - нужны ли для этого мозги - ты не поверишь!..
Как то возникает вопрос, а чем это данные так лучше функций и их можно инкапсулировать, а функции нельзя? Чем функции хуже\лучше? Это раз.
Два. Если предполагается использовать некоторый объект для инкапсуляции функций, то чем эти функции отличаются от данных тогда(Объект это же некоторые данные, не так ли?)? И зачем тогда городить доп. абстракцию(класс для того, чтобы превратить функцию из `функции` в `данные`), если они и так могут считаться данными?
По поводу тестирования. А не проще ли вместо ввода такой структуры инкапсуляции функций сделать структуру тестов, которая может юзать функции и данные как ей заблагорассудиться(или с некими более широкими возможностями вызова инкапсулированных методов относительно рантайма)? Чем такой вариант хуже будет?
п.с. говорим о каком-то конкретном языке или о сферическом в вакууме?
п.с.с. что-то как-то это всё подозрительно напоминает модульное программирование.
НАчнем-с
Инкапсуля́ция — свойство языка программирования, позволяющее объединить и защитить данные и код в объектe и скрыть реализацию объекта от пользователя (прикладного программиста). При этом пользователю предоставляется только спецификация (интерфейс) объекта.
Кратко: инкапсуляция - сокрытие реализации за интерфейсом. Т.е. видим интерфейс, а реализацию не видим.
По поводу юниттестов. Предполагается, что тестируется именно интерфейс класса, а реализация при этом - черный ящик.
Хотя, иногда так хочется потестировать и внутренности...
Почему приватные методы имеют право быть - да потому, что полезно "разделять и властвовать", а ещё и переиспользовать код. Поэтому паблик методы могут дробиться на несколько. А почему эти части не могут быть так же паблик? Да потому, что может накладываться некоторые ограничения на их использование. Зная, что приватные методы будут использоваться только теми, кто пишет класс, можно много чего оптимизировать (схалявить).
Как один из примеров, проверки на входные значения только у паблик методов, а "свои люди" (приватные) проходят без фейс-контроля. Или такой пример: некоторые методы должны вызываться в строгой последовательности, например для какого-нибудь строкового класса вызов copy_ только после allocate_.
Ну а про приватные данные, наверное, и говорить не стоит.
1. Такие методи должны еметь доступ к внутреннему состоянию класса "А". Тоесть его инкапсуляцыя должна быть нарушена.
2. Если класс "Помошник" буден пабликом то он только намусорит в интерфейсе розрабатываемого модуля. Если ето будет некий конфиденциальный класс - то зачем ему тогда паблик методы?
3. Одна задача розрезана на 2 класса что усложняет понимание и читабельность.
Я понимаю что часто приходится делать некие хелперы (свои валидаторы, логера, парсеры) и использовать их во всем модуле. Но в таком случае делается некий вспомагательный модуть common с такими сервисніми класами и используется только в кишках модуля интерфейс которого будет предоставлятся наружу.
Согласен, данный пример ни о чем, но если его расширить: добавить в конструктор чтение значений из файла, а в деструктор запись значений в файл, то может получиться некий объект, содержащий, допустим, настройки программы. В реальности я примерно так и делал, только члены приватные были, а их значения через методы устанавливались.
Можно конечно извратиться и специальный комментарий ставить у меняемых методов класса, и менять потом заточенной на этот комментарий утилитой. Но как-то не изящно.
500 может многовато, но 100 штук в одной программе среднего размера вполне может быть, если соблюдать принцип "один класс - одна обязанность".
1. Данные должен править хозяин данных. Так проще определить, где они были изменены. Функции же у большинства популярных языков не меняются извне.
2. Характер функции можно переопределить. Данные менее гибкие.
3. Обязанности класса определяются его функциями.
Не дополнительные абстракции, а грамотное распределение обязанностей. Эти функции будут лучше данных тем, что я смогу их отдельно протестировать без хакерства.
А как тестировать инкапсулированные методы? С помощью хакерства?
О языке, который поддерживает ООП.
Хотя, иногда так хочется потестировать и внутренности...
Моя литература утверждает, что при юниттестах используется белый ящик. Могу поискать цитаты, если интересно.
Как один из примеров, проверки на входные значения только у паблик методов, а "свои люди" (приватные) проходят без фейс-контроля. Или такой пример: некоторые методы должны вызываться в строгой последовательности, например для какого-нибудь строкового класса вызов copy_ только после allocate_.
Так и не понял, как это противоречит способу, когда выносятся все приватные методы в отдельный класс.
Мой опыт такой: когда я анализирую класс по его обязанности, то обычно выходит, что обязанность определяется его паблик методами. Значит приватными методами он выполняет не свои обязанности. Отсюда напрашивается рефакторинг - выделение класса.
Помощник не должен знать о классе "А". Зачем? Все нужные данные он получает в конструкторе. О классе "А" он естественно ничего не должен знать. Тем более, что вместо класса "А" его может использовать класс "Б", например, тестирующий класс.
Но это другое дело. Ведь ты, например, можешь решить, что настройки будут сохраняться в файл не в деструкторе, а в каждом сеттере. При этом внешние объекты не заметят разницы в поведении класса.
Для чего нужны юнит-тесты?
Когда заказчик в очередной раз попросит меня внести изменения в программу, когда я их внесу, то вот эти самые тесты запущу, чтобы убедиться, что не внёс ошибок своими правками. Это только половина их назначения. Вторая половина - создавать гибкую ООПшную структуру кода.
А ты предлагаешь мне во-первых помнить какие методы были приватными для 500 классов, править их при каждом чихе заказчика, во вторых, ты предлагаешь отказаться от второго назначения юнит-тестов.
Юнит-тесты, говоришь?
Если ошибка в приват-методах, то умолчим о квалификации программиста. Эти методы должны быть настолько вылизаны еще до внедрения в объект, что ошибка в них должна исключаться на 100%. Это внутренняя логика программы, она должна быть отработана еще на бумаге, до того, как становится кодом. Это раз.
Ты пишешь, что юнит-тесты должны "создавать гибкую ООПшную структуру кода". Что же ты понимаешь под словом гибкий? Если какой-то метод мешает отладке, то, имхо, уже структура не гибкая.
Также она будет гибкой только в том случае, если изменение 1го параметра (с паблика на приват, который и так был изначально приватным) потянет минимум изменений в других местах многотысячного кода. Я прав? Или что тогда "гибкий"?
В-третьих, локализовать ошибку нэ? В 90% случаях ошибка локализовывается в течении 1 дня (дебагер рулит), то есть, мы узнаем в каком модуле неисправность. А там уже тянем за зависимости и получаем, что проверить надо не весь код, а только его малую часть. При четком описании ошибки это сделать не так уж и сложно. Да и при его отсутствии не так, как кажется на первый взгляд.
А когда ошибка локализована, то отдельный модeль и тестируй до посинения, хоть все методы делай паблик и тестируй напрямую.
Алсо, 500 классов, это откуда цифра? Я, считая себя далеко не сторонником ООП, частенько обхожусь 10-20 своими классами не в самых мелких проектах, главное не дробить до элементарщины, а все же оставаться в рамках разумного. Сопротивляюсь введению каждого нового класса, пока он не докажет свою необходимость.
Единственные вещи, которые нуждаются в классе на 100% - это контейнеры чего-либо. Ну и немного мишуры к ним для удобства. Остальные классы - блаж.
Стандартный способ:
- отключаем предупреждение; pragma и т. п.
- финт ушами;
- включаем предупреждение.
Но предупреждение должно быть, если не отключено самим человеком!
Я не говорил, что предупреждений не должно быть. Моя позиция, что сам программист решает, какое предупреждение обосновано, а какое из-за непонятливости компилятора. И уж тем более, какое исправлять, а какое оставлять.
С опытом просто предупреждений становится все меньше и меньше, поэтому, те, которые остались уже скорее всего аномальные.
Когда в сильные снегопады...
Я не говорю, что дворник=дебил. Суть того высказывания, что каждый должен быть на своем месте. Просто сложилась ситуация, когда в программисты идут из-за того, что это молодежно и модно. Хотя сами не дружат с элементарной математикой. И для них надо упрощать/усложнять IDE?
Моя литература утверждает, что при юниттестах используется белый ящик. Могу поискать цитаты, если интересно.
Неа, не интересно. Тестировать или нет приватные члены - это старый холивар. Поэтому священной литературы обоих конфессий существует огромное количество. Твоя литература, видимо, описывает взгляд одной стороны.
Так и не понял, как это противоречит способу, когда выносятся все приватные методы в отдельный класс.
Ещё сложнее из моего поста понять причины французской революции... :)
Я ещё и не начинал высказываться на счет вынесения приватных методов.
Мой опыт такой: когда я анализирую класс по его обязанности, то обычно выходит, что обязанность определяется его паблик методами. Значит приватными методами он выполняет не свои обязанности. Отсюда напрашивается рефакторинг - выделение класса.
Т.е. у класса не может быть реализации, а только интерфейс?
Можно разбить код паблик метода на несколько методов для читабельности, и от этого класс перестанет выполнять свои обязанности?
Как пример
было
{
sum = 0;
for(int i=0; i < _items.size(); ++i)
{
sum += _item.value;
}
return sum / _items.size();
}
стало:
{
return _calcSum() / _items.size();
}
И что, теперь? Класс стал "выполнять не свои обязанности"?
Теперь надо создать отдельный класс, выносить туда все приватные члены?
У меня есть предположение, что у тебя была ситуация с некоторой плохой архитектурой класса. Где, действительно, часть реализации было правильным вынести в отдельную сущность. И у тебя сложилось мнение, что это и есть "универсальная таблЭтка", "серебряная пуля" для приватных членов.
Только в этом случае вынесение реализации было скорее всего делом логичной архитектура, а не необходимостью тестирования.
Не дополнительные абстракции, а грамотное распределение обязанностей. Эти функции будут лучше данных тем, что я смогу их отдельно протестировать без хакерства.
Усложнение архитектуры ради одного тестирования в ущерб читабельности и простоты поддержки, - это не есть "грамотное распределение обязанностей"
Честно говоря, мне даже не совсем понятно, как ты собираешься тотально вынести приватные методы в отдельный класс. А как же приватные данные? Они тоже перенесутся в этот вспомогательный класс?
И видимо этот "помощник" должен быть тотально пабликом?
Т.е. любой класс в реальности это будет два класса: этакий "интерфейс+" у которого интерфейс требуемого класса и часть реализации в паблик методах, причем как я понял никакого внутреннего состояния, т.к. все внутреннее состояние и реализация в другом "вспомогательном классе". Т.е. в реальности ВСЁ в вспомогательном классе, а основной класс - просто пустышка?
Только вот связанность этих классов получится на столько сильной, что практически нельзя будет изменить один класс не изменив другой. Аналогично и с тестами.
Да и зачем городить огород? Зачем все усложнять?
Ради тестирования? Да нафиг такое тестирование, для которого надо так усложнять систему. Это введет только ещё больше вероятностей ошибок.
А как тестировать инкапсулированные методы? С помощью хакерства?
А зачем их отдельно тестировать?
Тестируй через интерфейс класса.
трудно сказать, что такое "программа среднего размера", но 100 классов...
какбы лично я обьединяю в класс методы некого схожего типа функциональности. типа в класс "Копать", включены методы "экскаватор" и "лопата". простите, но чота я нихрена из вашего поста не понял, УК. как моно наплодить сто классов в одной "среднего размера" программе.
было
{
sum = 0;
for(int i=0; i < _items.size(); ++i)
{
sum += _item.value;
}
return sum / _items.size();
}
стало:
{
return _calcSum() / _items.size();
}
И что, теперь? Класс стал "выполнять не свои обязанности"?
Теперь надо создать отдельный класс, выносить туда все приватные члены?
Для ответа на вопросы мне надо полный класс и описание его обязанности. Из того, что приведено можно пока составить только класс, который пытается собой заменить функцию типа:
float calcArithmeticMean(SomeType items)
Если не ошибаюсь, в Питоне нет условной компиляции. Ну как в C/C++/C# можно сделать версии Debug и Release: в первую напихать разных тестов, а во второй не будет ничего лишнего - всё само выкинется при компиляции в релизе. А в Питоне придётся убирать тесты ручками, так? Или я неправ?
Если это действительно так, то нужно не задаваться вопросом, как побороть недостаток языка, а взять другой язык.
Мне тебя тоже трудно понять. В моём понимании "Копать" - это метод, а "экскаватор" и "лопата" - объекты (или классы). И названные объекты тоже состоят из объектов у которых есть названия.
Нет, ты не понял. Тесты не пихаются в приложение, которое реализует требования ТЗ. Тесты содержатся в отдельном приложении, смысл которого - тестировать.
На счёт условной компиляции - это юмор, наверное. Даже в C++ можно сделать с помощью make-файлов кучу версий с разными включениями, а не только Debug и Release (и в каждой версии выбрать - включать отладочную информацию или нет). В Python ещё гибче, так как можно на ходу выбирать, какие модули будем подключать.
И я про то же! Программист сам должен решать, какие ворнинги отключать. Но изначально они должны быть!
Но неопытных-то большинство! И нужно сделать так, чтобы их ошибки автоматически отлавливались компилятором.
Иначе эти ошибки джуниоров придётся отлавливать тим-лидам. Что дорого и нелогично.
Зато я говорю: дворники - дебилы. Вернее, так: в среднем среди людей 95% дебилов, а среди дворников - 100%.
Чтобы избежать обвинений в снобизме, скажу, что возможно я сам попадаю в эти 95%. Со стороны виднее.
Я к чему клоню: дай дворнику лопату, которая сама будет чистить снег - и производительность труда вырастет, завалы снега исчезнут. Дай программеру умную среду разработки - и качество кода вырастет, программы станут почти безбажными.
Точнее даже так: качество работы дворника проверяет мастер (или кто там у них), а качество работы программиста может и должен проверять компилятор - ведь это легко осуществимо, а значит дёшево.
Да, нужно упрощать (где нужно) и усложнять (где нужно): если так много неучей, то пусть умные создадут для них такую среду, чтобы они делали меньше ошибок. Это пойдёт на пользу всему обществу. В итоге мы все будем жить лучше (пафос, да, - это я люблю).
У меня в шарпе пихаются :). Зачем мне ещё одно приложение? Дело-то в том, что в итоговой программе ничего лишнего не будет - всё выкинется само.
Ну почему юмор? Конечно, кроме условной компиляции есть другие средства (в C# специальные классы Debug и Trace, атрибут Conditional), но суть в том, что с их помощью я вставляю отладочную информацию в программу, которая используется в одной из конфигураций (Debug или другая, их можно создать сколько угодно), а в релизе ничего этого не будет.
Так я не понял: можно ли в Python сделать так, чтобы в одной конфигурации тесты выполнялись, а в другой - выкидывались? Причём переключение с одной конфигурации на другую должно происходить в пару кликов мышкой или пару строк кода.
Затем, что тестируя модуль ты тестируешь модуль, а не всё приложение. Затем, что для выполнения автоматических тестов не нужно компилировать, собирать и запускать главное приложение.
И чтобы не получить неожиданных эффектов, когда поведение сборок будет странным образом отличаться.
Кликом мышкой нельзя ни в одном языке :)
Кодом - пожалуйста. Например:
import test_something
else:
import something
В общем, как и в C++ почти.
float calcArithmeticMean(SomeType items)
Это пример и в нем вполне достаточно данных для примера.
Он ничего не пытается, в нем просто есть такой метод.
Остальное не важно.
Но неопытных-то большинство! И нужно сделать так, чтобы их ошибки автоматически отлавливались компилятором.
Иначе эти ошибки джуниоров придётся отлавливать тим-лидам. Что дорого и нелогично.
Имхо, лучше подтянуть тим-лидом парочку молодых, а не молча отлавливать баги, заперевшись в каморке без окон. Все равно варнинги останутся, но если новичек способный, то он и сам с ними разберется после парочки мастер-классов.
Ошибки отлавливать надо, но не варнинги. Надо понять, что предупреждение - это, собственно, предупреждение. Рассмотреть его и уже выносить приговор: казнить или миловать. Но возводить ужасающие рамки тоже не вариант, ибо даже самый матерый программист будет плевать на все варнинги, если только 1% будет толковыми.
Пример нынешнего моего варнинга:
Зато я говорю: дворники - дебилы. Вернее, так: в среднем среди людей 95% дебилов, а среди дворников - 100%.
...
Вырастит качество, но за все надо платить. "Умная" среда или будет генерировать медленный/нестабильный код, или добавит еще какой половник дегтя.
Машины лет 20-40 не смогут отличаться творчеством (только статистическая переработка существующих произведений). ПК же этого не смогут еще лет 50-100. Так что, до этого момента надо ровняться не на людей, которые о регистрах в процессоре не знают, а LIFO пустое сочетание букв.
Да, нужно упрощать (где нужно) и усложнять (где нужно): если так много неучей, то пусть умные создадут для них такую среду, чтобы они делали меньше ошибок. Это пойдёт на пользу всему обществу. В итоге мы все будем жить лучше (пафос, да, - это я люблю).
У меня менее оптимистичные прогнозы, по использованию неучей. Какие бы ты палки не давал мартышки, больше одного раза она все равно не будет ими пользоваться. Так и тут, какой бы ты инструмент не доверил дебилу, он им все равно не сможет пользоваться корректно.
Согласен. Вполне достаточно данных для того, чтобы сказать, что пример неудачен.
Зачем городить класс там, где можно обойтись методом, тем более что у него большой потенциал повторного использования? Велика вероятность, что и другим классам могут потребоваться функции calcArithmeticMean, calcSum. Более того, sum (accumulate) есть в стандартных библиотеках известных мне языков, что подтверждает мысль о повторном использовании.
И видимо этот "помощник" должен быть тотально пабликом?
Т.е. любой класс в реальности это будет два класса: этакий "интерфейс+" у которого интерфейс требуемого класса и часть реализации в паблик методах, причем как я понял никакого внутреннего состояния, т.к. все внутреннее состояние и реализация в другом "вспомогательном классе". Т.е. в реальности ВСЁ в вспомогательном классе, а основной класс - просто пустышка?
Не совсем пустышкой. Он будет реализовывать свои открытые методы. Классы внутренних объектов - свои открытые методы, их внутренние объекты - свои и т.д. пока не дойдем до класса, у которого останутся только простые внутренние объекты.
Не всегда есть время на такое "развёртывание" в маленьких проектах, но в больших проектах оно должно экономить время, за счёт того, что каждый класс имеет одну обязанность, то есть, может использоваться более часто. Это устранит дублирование.
Не совсем так. Класс-помощник будет независим от главного. У него будет потенциал использования в другом классе.
Для того, чтобы использовать код повторно. У нас косвенно выйдет так, что каждый класс пройдёт проверку на альтернативное использование путём использования в тесте.
Таки можно! Глянь картинко - выбор конфигурации кликом мышки :)
Я ж говорю - выкинь свою IDE, возьми нормальную :D
Перейди на нормальный язык со статической типизацией - это махом решит кучу проблем с тестами ;)
koodeer, не заставляй меня усомниться в тебе и спутать с людьми, которые путают язык и IDE.
Но всё-таки создаётся впечатление, что весь сыр-бор с инкапсуляцией и тестированием вызван как раз динамической природой используемого тобой языка. В статике нет нужды писать тест на каждый чих.
Хотя ты же и на C++ пишешь. Не понимаю...
Продолжай дискуссию, авось что-то прояснится.