Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Инкапсуляция

87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Уже обсуждали циклы, шаблоны. Возможно, кому-то будет интересна тема инкапсуляции. Тут я буду говорить именно о той, которая определяется синтаксисом, ключевыми словами типа private, protected и т.п. Кто что про неё думает? Нужна ли она вообще?

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

Но и с данными должна быть некая условная инкапсуляция. То есть должен быть не полный запрет, а генерирование предупреждений компилятором (интерпретатором) в случае их использования. Такой подход может пригодиться при рефакторингах.
Страницы:
33K
27 января 2011 года
hivewarrior
205 / / 16.11.2010
Цитата: Kogrom

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

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



Приватные матоды себя не оправдывают только в том случаи, если разработка идет в тесном коллективе не более 3х человек. Иначе любой индус, не до конца понимая всего божественного замысла создателя класса, начинает писать молитвы Шиве на языке программирования, что частенько приводит к интересным ошибкам. Так что приватные методы/данные очень даже помогают в разработке больших комплексов (а при разработке маленьких комплексов я считаю и ООП излишнем, но уже что-либо поделать поздно...)

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

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

Неполный запрет убьет всю суть защиты внутренностей класса. Как часто программист смотрит на предупреждения компилятором? Я только через раз, да и то на половину плюю, ибо знаю, код там вполне рабочий и каждый миллиметр там вылизан, как у кота яйца. Просто принимаю предупреждения к сведению и если они весомы, то тогда уже и исправляю.

Как-то так:rolleyes:

87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hivewarrior
Иначе любой индус, не до конца понимая всего божественного замысла создателя класса, начинает писать молитвы Шиве на языке программирования, что частенько приводит к интересным ошибкам.


Какие молитвы? Приватных методов не должно быть не потому, что они должны стать открытыми. Их вообще не должно быть в конкретном классе.

Цитата: hivewarrior
На счет тестирования. Что мешает отладить приват метод, как паблик, а уже потом думать, чем же он будет в конце концов?


А как же unit-тесты? Они же выполняются пока жива программа.

Цитата: hivewarrior
Как часто программист смотрит на предупреждения компилятором?


Профессиональный программист - всегда, когда они появляются. Но это отдельная тема.

33K
27 января 2011 года
hivewarrior
205 / / 16.11.2010
Цитата: Kogrom
Какие молитвы? Приватных методов не должно быть не потому, что они должны стать открытыми. Их вообще не должно быть в конкретном классе.


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

Шаловливые ручки индусов частенько пытаются сделать очень интересные вещи с результатами функций, которые возвращают указатели на объекты, которые трогать не их ума дело. А трогать надо по логике, но не им. Вот и приходят приват методы.

Или я тебя не так понял? На что тогда предлагаешь заменять приват методы? Альтернатива защиты критичных данных?

Цитата: Kogrom

А как же unit-тесты? Они же выполняются пока жива программа.


Что мешает проводить юнит-тесты для модулей, пока они паблик. Потом, когда передаешь их заказчику, закрываешь критичные методы/данные в приват. Тестируешь еще раз, на то, не переусердствовал ли ты. Все.

Цитата: Kogrom

Профессиональный программист - всегда, когда они появляются. Но это отдельная тема.



 
Код:
int main();
{
int a=1;
if(a>1)
    return 0;
else if(a=<1)
   return 1;
}

В MS C++ 6.0 выдаст предупреждение, что не все пути возврата функции предусмотрены. Но мы то видим, что это не так. Предупреждение есть. Взглянуть взглянул, ну а толку?
87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hivewarrior
Или я тебя не так понял? На что тогда предлагаешь заменять приват методы? Альтернатива защиты критичных данных?


Создаем ещё один класс для внутреннего объекта, в который перенесём все эти методы. Вместо обращений к приватным методам будет обращаться к открытым методам приватного объекта. Оно и по распределению обязанностей выйдет вернее. Я же написал об этом сразу.

Цитата: hivewarrior
Что мешает проводить юнит-тесты для модулей, пока они паблик. Потом, когда передаешь их заказчику, закрываешь критичные методы/данные в приват.


Мешает их смысл.

Цитата: hivewarrior
 
Код:
int main();
{
int a=1;
if(a>1)
    return 0;
else if(a=<1)
   return 1;
}

В MS C++ 6.0 выдаст предупреждение, что не все пути возврата функции предусмотрены. Но мы то видим, что это не так. Предупреждение есть. Взглянуть взглянул, ну а толку?


Толк есть. По смыслу тут надо что-то такое:

 
Код:
int main();
{
    int a=1;
    if(a>1)
       return 0;
    else
       return 1;
}
297
27 января 2011 года
koodeer
1.2K / / 02.05.2009
Kogrom, ты не прав! :)

Великие отцы программирования ещё в прошлые десятилетия спорили на тему инкапсуляции. Были те кто говорили, что она не нужна. Но по прошествии времени все изменили своё мнение.

Будь моя воля, я бы закрывал всё и вся!
Например в C# мне сильно не хватает статических переменных методов (то, что есть в C и C++). То есть нужна такая переменная внутри метода, которая сохраняет своё значение между вызовами этого метода. Почему из шарпа это убрали - не представляю. Приходится юзать поля класса для этой цели.

Цитата: Kogrom
Создаем ещё один класс для внутреннего объекта, в который перенесём все эти методы. Вместо обращений к приватным методам будет обращаться к открытым методам приватного объекта. Оно и по распределению обязанностей выйдет вернее.


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


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

11
27 января 2011 года
oxotnik333
2.9K / / 03.08.2007
Цитата: Kogrom

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


О каких тестах идет речь? В чем неудобство?

Цитата: Kogrom

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


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

33K
27 января 2011 года
hivewarrior
205 / / 16.11.2010
Цитата: Kogrom
Создаем ещё один класс для внутреннего объекта, в который перенесём все эти методы. Вместо обращений к приватным методам будет обращаться к открытым методам приватного объекта. Оно и по распределению обязанностей выйдет вернее. Я же написал об этом сразу.



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

Создавать объекты для этого? То какого типа и какие? Это все равно, что вместо массива указателей на функции использовать извращения с классами. Можно - можно, но как-то противоестественно.

Цитата: Kogrom

Мешает их смысл.


Это ты неправильно подходишь к задаче просто.
Мой подход:
1) Создаем класс с интерфейсами
2) Отладка с помощью юнит-тестов
3) Защита "от дурака" с помощью приват методов
4) Отладка с помощью юнит-тестов

Всегда работать легче, разбив задачу на много подзадач. В данном случаи подзадач две. "Создать рабочий класс" и "Создать защиту от дураков". Для каждой задачи свои юнит-тесты, во многом дублирующие друг друга, но тем проще - не надо изобретать новые.

Цитата: Kogrom

Толк есть. По смыслу тут надо что-то такое:
 
Код:
int main();
{
    int a=1;
    if(a>1)
       return 0;
    else
       return 1;
}



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

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

Смотреть на них стоит, но не все они должны восприниматься всерьез.

11
27 января 2011 года
oxotnik333
2.9K / / 03.08.2007
Цитата: koodeer

Например в C# мне сильно не хватает статических переменных методов (то, что есть в C и C++). То есть нужна такая переменная внутри метода, которая сохраняет своё значение между вызовами этого метода. Почему из шарпа это убрали - не представляю. Приходится юзать поля класса для этой цели.


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

Цитата: koodeer

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


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

87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Помнится, не так давно в одной теме ты говорил, что вложенные классы не нужны. Якобы это усложняет код. А теперь, в попытке избавиться от приватных методов, оказались нужны? :)


Я говорю не про вложенный класс, а про агрегированный объект. Класс будет обычным.

Цитата: koodeer
Насчёт предупреждений компилятора. Да, конечно, профессиональный программист на них смотрит, и добивается их отсутствия. Но таковых меньшинство. Всегда было и будет большинство начинающих программеров, а отсюда - быдлокод. Поэтому лучше не полагаться на разум человека, а добавить строгости в язык/компилятор/IDE.


То есть надо равняться на отстающих?

Цитата: oxotnik333
О каких тестах идет речь?


http://ru.wikipedia.org/wiki/Модульное_тестирование

Цитата: oxotnik333
Данные не обязательно должны быть сокрыты...


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

87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hivewarrior
Это ты неправильно подходишь к задаче просто.


Безусловно. Но я бы тебе рекомендовал всё же поближе ознакомиться что такое регрессионное тестирование, прежде чем такое утверждать. Не горячись, выдержи паузу :)

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


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

11
27 января 2011 года
oxotnik333
2.9K / / 03.08.2007


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

Цитата: Kogrom

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


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

Код:
class SomeClass
{
    int value;
    void printValue()
        {
             cout<<value;
        }
};
int main()
{
      ComeClass obj;
      obj.value = 10;
      obj.printValue();
      return 0;
}

без инкапсуляции код сократился минимум на 3 строки, с ней надо было бы делать сеттер для ComeClass::value
87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: oxotnik333
к примеру
Код:
class SomeClass
{
    int value;
    void printValue()
        {
             cout<<value;
        }
};
int main()
{
      ComeClass obj;
      obj.value = 10;
      obj.printValue();
      return 0;
}

без инкапсуляции код сократился минимум на 3 строки, с ней надо было бы делать сеттер для SomeClass::value


Возможно, мой вопрос покажется странным, но... Какое назначение у SomeClass? Если смысла нет, то пример неудачен.

33K
27 января 2011 года
hivewarrior
205 / / 16.11.2010
Цитата: Kogrom
Безусловно. Но я бы тебе рекомендовал всё же поближе ознакомиться что такое регрессионное тестирование, прежде чем такое утверждать. Не горячись, выдержи паузу :)



Хорошо. Как приватные методы мешают тестированию? Их всегда можно переобъявить как паблик, а потом тестировать до посинения, но учитывать, что они в будущем станут приватными. Потом после исправления ошибки снова использовать как приват.
После переобъявления их как приват проводим еще пару тестов (а скорее всего их проведет сам компилятор, который заругается там, где нужно).

Цитата: Kogrom

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



Ассемблерный код, как эквивалент быстродействию.
А на счет понятности, то дело вкуса.

Это банальный пример предупреждения, которое на качество кода имеет посредственное влияние, но тем не менее присутствует. Я же не кричу: "Я пишу так, и все пишите!" Это пример предупреждения, которое воспринимать можно философски, не исправляя его, проблем оно не принесет.

Были у меня и более интересные предупреждения, которые просто непонятно как были получены IDE. Код верный, но предупреждение стоит. Я их на листочек не записывал.

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

Цитата: koodeer
Насчёт предупреждений компилятора. Да, конечно, профессиональный программист на них смотрит, и добивается их отсутствия. Но таковых меньшинство. Всегда было и будет большинство начинающих программеров, а отсюда - быдлокод. Поэтому лучше не полагаться на разум человека, а добавить строгости в язык/компилятор/IDE.



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

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

87
27 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: hivewarrior
Хорошо. Как приватные методы мешают тестированию? Их всегда можно переобъявить как паблик, а потом тестировать до посинения, но учитывать, что они в будущем станут приватными. Потом после исправления ошибки снова использовать как приват.
После переобъявления их как приват проводим еще пару тестов (а скорее всего их проведет сам компилятор, который заругается там, где нужно).



Ты не выдержал паузы. Я разочарован. Эх...

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

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

297
27 января 2011 года
koodeer
1.2K / / 02.05.2009
Цитата: oxotnik333
ИМХО логичнее использовать поле класса, нежели плодить статические переменные, в которых потом запутаться легко будет.


Хмм, на мой взгляд, легче запутаться в лишних полях класса. Это поле можно случайно изменить в другом методе, это поле видно в списке членов класса (хотя оно там не нужно), etc.

Цитата: oxotnik333
Очень часто на форумах от новичков всплывает вопрос типа "мне компилятор выдал ворнинг", на что местные гуру отвечают "забей на варнинги, все ок у тебя". Так что у самих новичков интерес к ворнингам довольно таки большой, но недопрограммисты их отучают от этого интереса.


Подумал. Да, учту это, и впредь постараюсь сам подобного не советовать.



Цитата: Kogrom
То есть надо равняться на отстающих?


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

262
27 января 2011 года
Iktomy
1.2K / / 11.10.2004
Хотел написать про использоваине приватных методов и переменных в классах, но потом смотрю - про тестирование.

Ладно, буду молчать.

А нет, кое что скажу:
Цитата:
мне во-первых помнить какие методы были приватными для 500 классов, править их при каждом чихе заказчика


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

297
27 января 2011 года
koodeer
1.2K / / 02.05.2009
Цитата: oxotnik333
класс - черный ящик с входом и выходом, на вход подаем все мыслимые параметры, с выхода принимаем, то как он их обработал, какую здесь пользу сокрытие принесет не представляю.


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

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


Стандартный способ:
- отключаем предупреждение; pragma и т. п.
- финт ушами;
- включаем предупреждение.
Но предупреждение должно быть, если не отключено самим человеком!

Цитата: hivewarrior
Лучше полагаться на то, что человек без разума не полезет не в свое \, а будет мести улицы или лить сталь.


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

2.1K
27 января 2011 года
Norgat
452 / / 12.08.2009
Цитата: Kogrom
Моё мнение следующее. Понятно, что инкапсуляция полезна для данных - каждый объект должен сам разбираться со своими данными. Но приватные методы не нужны, ибо их неудобно тестировать, они показывают недостатки дизайна. Лучше передать эти методы в какой-либо агрегированный объект.



Как то возникает вопрос, а чем это данные так лучше функций и их можно инкапсулировать, а функции нельзя? Чем функции хуже\лучше? Это раз.

Два. Если предполагается использовать некоторый объект для инкапсуляции функций, то чем эти функции отличаются от данных тогда(Объект это же некоторые данные, не так ли?)? И зачем тогда городить доп. абстракцию(класс для того, чтобы превратить функцию из `функции` в `данные`), если они и так могут считаться данными?


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

п.с. говорим о каком-то конкретном языке или о сферическом в вакууме?

п.с.с. что-то как-то это всё подозрительно напоминает модульное программирование.

3
27 января 2011 года
Green
4.8K / / 20.01.2000
Что-то давно я не холиварил... :)
НАчнем-с

Цитата:

Инкапсуля&#769;ция — свойство языка программирования, позволяющее объединить и защитить данные и код в объектe и скрыть реализацию объекта от пользователя (прикладного программиста). При этом пользователю предоставляется только спецификация (интерфейс) объекта.



Кратко: инкапсуляция - сокрытие реализации за интерфейсом. Т.е. видим интерфейс, а реализацию не видим.

По поводу юниттестов. Предполагается, что тестируется именно интерфейс класса, а реализация при этом - черный ящик.
Хотя, иногда так хочется потестировать и внутренности...

Почему приватные методы имеют право быть - да потому, что полезно "разделять и властвовать", а ещё и переиспользовать код. Поэтому паблик методы могут дробиться на несколько. А почему эти части не могут быть так же паблик? Да потому, что может накладываться некоторые ограничения на их использование. Зная, что приватные методы будут использоваться только теми, кто пишет класс, можно много чего оптимизировать (схалявить).
Как один из примеров, проверки на входные значения только у паблик методов, а "свои люди" (приватные) проходят без фейс-контроля. Или такой пример: некоторые методы должны вызываться в строгой последовательности, например для какого-нибудь строкового класса вызов copy_ только после allocate_.

Ну а про приватные данные, наверное, и говорить не стоит.

276
27 января 2011 года
Rebbit
1.1K / / 01.08.2005
Переносить приватные методи класа "А" в другой клас (назовем его "Помошник") и делать их неприватными смысла не вижу. Вижу только недостатки.

1. Такие методи должны еметь доступ к внутреннему состоянию класса "А". Тоесть его инкапсуляцыя должна быть нарушена.

2. Если класс "Помошник" буден пабликом то он только намусорит в интерфейсе розрабатываемого модуля. Если ето будет некий конфиденциальный класс - то зачем ему тогда паблик методы?

3. Одна задача розрезана на 2 класса что усложняет понимание и читабельность.

Я понимаю что часто приходится делать некие хелперы (свои валидаторы, логера, парсеры) и использовать их во всем модуле. Но в таком случае делается некий вспомагательный модуть common с такими сервисніми класами и используется только в кишках модуля интерфейс которого будет предоставлятся наружу.
11
27 января 2011 года
oxotnik333
2.9K / / 03.08.2007
Цитата: Kogrom
Возможно, мой вопрос покажется странным, но... Какое назначение у SomeClass? Если смысла нет, то пример неудачен.


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

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Iktomy
УК, если есть чоткая структура программы, то правка не представится таким уж большим делом.


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

Цитата: Iktomy
и это, про пиццот классов - это же умом тронутся. это что, новый фреймворк какой-то или просто сказали?


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

Цитата: Norgat
Как то возникает вопрос, а чем это данные так лучше функций и их можно инкапсулировать, а функции нельзя? Чем функции хуже\лучше? Это раз.


1. Данные должен править хозяин данных. Так проще определить, где они были изменены. Функции же у большинства популярных языков не меняются извне.
2. Характер функции можно переопределить. Данные менее гибкие.
3. Обязанности класса определяются его функциями.

Цитата: Norgat
Два. Если предполагается использовать некоторый объект для инкапсуляции функций, то чем эти функции отличаются от данных тогда(Объект это же некоторые данные, не так ли?)? И зачем тогда городить доп. абстракцию(класс для того, чтобы превратить функцию из `функции` в `данные`), если они и так могут считаться данными?


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

Цитата: Norgat
По поводу тестирования. А не проще ли вместо ввода такой структуры инкапсуляции функций сделать структуру тестов, которая может юзать функции и данные как ей заблагорассудиться(или с некими более широкими возможностями вызова инкапсулированных методов относительно рантайма)? Чем такой вариант хуже будет?


А как тестировать инкапсулированные методы? С помощью хакерства?

Цитата: Norgat
п.с. говорим о каком-то конкретном языке или о сферическом в вакууме?


О языке, который поддерживает ООП.

Цитата: Green
По поводу юниттестов. Предполагается, что тестируется именно интерфейс класса, а реализация при этом - черный ящик.
Хотя, иногда так хочется потестировать и внутренности...


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

Цитата: Green
Почему приватные методы имеют право быть - да потому, что полезно "разделять и властвовать", а ещё и переиспользовать код. Поэтому паблик методы могут дробиться на несколько. А почему эти части не могут быть так же паблик? Да потому, что может накладываться некоторые ограничения на их использование. Зная, что приватные методы будут использоваться только теми, кто пишет класс, можно много чего оптимизировать (схалявить).
Как один из примеров, проверки на входные значения только у паблик методов, а "свои люди" (приватные) проходят без фейс-контроля. Или такой пример: некоторые методы должны вызываться в строгой последовательности, например для какого-нибудь строкового класса вызов copy_ только после allocate_.


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

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

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Rebbit
1. Такие методи должны еметь доступ к внутреннему состоянию класса "А". Тоесть его инкапсуляцыя должна быть нарушена.


Помощник не должен знать о классе "А". Зачем? Все нужные данные он получает в конструкторе. О классе "А" он естественно ничего не должен знать. Тем более, что вместо класса "А" его может использовать класс "Б", например, тестирующий класс.

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


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

33K
28 января 2011 года
hivewarrior
205 / / 16.11.2010
Цитата: Kogrom
Ты не выдержал паузы. Я разочарован. Эх...

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

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



Юнит-тесты, говоришь?
Если ошибка в приват-методах, то умолчим о квалификации программиста. Эти методы должны быть настолько вылизаны еще до внедрения в объект, что ошибка в них должна исключаться на 100%. Это внутренняя логика программы, она должна быть отработана еще на бумаге, до того, как становится кодом. Это раз.

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

Также она будет гибкой только в том случае, если изменение 1го параметра (с паблика на приват, который и так был изначально приватным) потянет минимум изменений в других местах многотысячного кода. Я прав? Или что тогда "гибкий"?

В-третьих, локализовать ошибку нэ? В 90% случаях ошибка локализовывается в течении 1 дня (дебагер рулит), то есть, мы узнаем в каком модуле неисправность. А там уже тянем за зависимости и получаем, что проверить надо не весь код, а только его малую часть. При четком описании ошибки это сделать не так уж и сложно. Да и при его отсутствии не так, как кажется на первый взгляд.

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

Алсо, 500 классов, это откуда цифра? Я, считая себя далеко не сторонником ООП, частенько обхожусь 10-20 своими классами не в самых мелких проектах, главное не дробить до элементарщины, а все же оставаться в рамках разумного. Сопротивляюсь введению каждого нового класса, пока он не докажет свою необходимость.

Единственные вещи, которые нуждаются в классе на 100% - это контейнеры чего-либо. Ну и немного мишуры к ним для удобства. Остальные классы - блаж.

Цитата: koodeer

Стандартный способ:
- отключаем предупреждение; pragma и т. п.
- финт ушами;
- включаем предупреждение.
Но предупреждение должно быть, если не отключено самим человеком!



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

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

Цитата: koodeer

Когда в сильные снегопады...



Я не говорю, что дворник=дебил. Суть того высказывания, что каждый должен быть на своем месте. Просто сложилась ситуация, когда в программисты идут из-за того, что это молодежно и модно. Хотя сами не дружат с элементарной математикой. И для них надо упрощать/усложнять IDE?

3
28 января 2011 года
Green
4.8K / / 20.01.2000
Цитата: Kogrom

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


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

Цитата: Kogrom

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


Ещё сложнее из моего поста понять причины французской революции... :)
Я ещё и не начинал высказываться на счет вынесения приватных методов.

Цитата: Kogrom

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


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

Как пример
было

 
Код:
float SomeClass::calcArithmeticMean()
{
    sum = 0;
    for(int i=0; i < _items.size(); ++i)
    {
        sum += _item.value;
    }
    return sum / _items.size();
}


стало:
 
Код:
float SomeClass::calcArithmeticMean()
{
    return _calcSum() / _items.size();
}

И что, теперь? Класс стал "выполнять не свои обязанности"?
Теперь надо создать отдельный класс, выносить туда все приватные члены?

У меня есть предположение, что у тебя была ситуация с некоторой плохой архитектурой класса. Где, действительно, часть реализации было правильным вынести в отдельную сущность. И у тебя сложилось мнение, что это и есть "универсальная таблЭтка", "серебряная пуля" для приватных членов.
Только в этом случае вынесение реализации было скорее всего делом логичной архитектура, а не необходимостью тестирования.

Цитата: Kogrom

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


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

Честно говоря, мне даже не совсем понятно, как ты собираешься тотально вынести приватные методы в отдельный класс. А как же приватные данные? Они тоже перенесутся в этот вспомогательный класс?
И видимо этот "помощник" должен быть тотально пабликом?
Т.е. любой класс в реальности это будет два класса: этакий "интерфейс+" у которого интерфейс требуемого класса и часть реализации в паблик методах, причем как я понял никакого внутреннего состояния, т.к. все внутреннее состояние и реализация в другом "вспомогательном классе". Т.е. в реальности ВСЁ в вспомогательном классе, а основной класс - просто пустышка?

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

Да и зачем городить огород? Зачем все усложнять?
Ради тестирования? Да нафиг такое тестирование, для которого надо так усложнять систему. Это введет только ещё больше вероятностей ошибок.

Цитата: Kogrom

А как тестировать инкапсулированные методы? С помощью хакерства?


А зачем их отдельно тестировать?
Тестируй через интерфейс класса.

262
28 января 2011 года
Iktomy
1.2K / / 11.10.2004
Цитата: Kogrom
500 может многовато, но 100 штук в одной программе среднего размера вполне может быть, если соблюдать принцип "один класс - одна обязанность".



трудно сказать, что такое "программа среднего размера", но 100 классов...

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

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Green
Как пример
было
 
Код:
float SomeClass::calcArithmeticMean()
{
    sum = 0;
    for(int i=0; i < _items.size(); ++i)
    {
        sum += _item.value;
    }
    return sum / _items.size();
}


стало:
 
Код:
float SomeClass::calcArithmeticMean()
{
    return _calcSum() / _items.size();
}

И что, теперь? Класс стал "выполнять не свои обязанности"?
Теперь надо создать отдельный класс, выносить туда все приватные члены?


Для ответа на вопросы мне надо полный класс и описание его обязанности. Из того, что приведено можно пока составить только класс, который пытается собой заменить функцию типа:
float calcArithmeticMean(SomeType items)

297
28 января 2011 года
koodeer
1.2K / / 02.05.2009
Кажется, я догадался, почему УК Kogrom задался таким вопросом.

Если не ошибаюсь, в Питоне нет условной компиляции. Ну как в C/C++/C# можно сделать версии Debug и Release: в первую напихать разных тестов, а во второй не будет ничего лишнего - всё само выкинется при компиляции в релизе. А в Питоне придётся убирать тесты ручками, так? Или я неправ?

Если это действительно так, то нужно не задаваться вопросом, как побороть недостаток языка, а взять другой язык.
87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Iktomy
какбы лично я обьединяю в класс методы некого схожего типа функциональности. типа в класс "Копать", включены методы "экскаватор" и "лопата".



Мне тебя тоже трудно понять. В моём понимании "Копать" - это метод, а "экскаватор" и "лопата" - объекты (или классы). И названные объекты тоже состоят из объектов у которых есть названия.

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Если не ошибаюсь, в Питоне нет условной компиляции. Ну как в C/C++/C# можно сделать версии Debug и Release: в первую напихать разных тестов, а во второй не будет ничего лишнего - всё само выкинется при компиляции в релизе. А в Питоне придётся убирать тесты ручками, так? Или я неправ?



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

На счёт условной компиляции - это юмор, наверное. Даже в C++ можно сделать с помощью make-файлов кучу версий с разными включениями, а не только Debug и Release (и в каждой версии выбрать - включать отладочную информацию или нет). В Python ещё гибче, так как можно на ходу выбирать, какие модули будем подключать.

297
28 января 2011 года
koodeer
1.2K / / 02.05.2009
Цитата: hivewarrior
Я не говорил, что предупреждений не должно быть. Моя позиция, что сам программист решает, какое предупреждение обосновано, а какое из-за непонятливости компилятора. И уж тем более, какое исправлять, а какое оставлять.


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

Цитата: hivewarrior
С опытом просто предупреждений становится все меньше и меньше, поэтому, те, которые остались уже скорее всего аномальные.


Но неопытных-то большинство! И нужно сделать так, чтобы их ошибки автоматически отлавливались компилятором.
Иначе эти ошибки джуниоров придётся отлавливать тим-лидам. Что дорого и нелогично.



Цитата: hivewarrior
Я не говорю, что дворник=дебил. Суть того высказывания, что каждый должен быть на своем месте.


Зато я говорю: дворники - дебилы. Вернее, так: в среднем среди людей 95% дебилов, а среди дворников - 100%.
Чтобы избежать обвинений в снобизме, скажу, что возможно я сам попадаю в эти 95%. Со стороны виднее.
Я к чему клоню: дай дворнику лопату, которая сама будет чистить снег - и производительность труда вырастет, завалы снега исчезнут. Дай программеру умную среду разработки - и качество кода вырастет, программы станут почти безбажными.
Точнее даже так: качество работы дворника проверяет мастер (или кто там у них), а качество работы программиста может и должен проверять компилятор - ведь это легко осуществимо, а значит дёшево.

Цитата: hivewarrior
Просто сложилась ситуация, когда в программисты идут из-за того, что это молодежно и модно. Хотя сами не дружат с элементарной математикой. И для них надо упрощать/усложнять IDE?


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

297
28 января 2011 года
koodeer
1.2K / / 02.05.2009
Цитата: Kogrom
Нет, ты не понял. Тесты не пихаются в приложение, которое реализует требования ТЗ. Тесты содержатся в отдельном приложении, смысл которого - тестировать.


У меня в шарпе пихаются :). Зачем мне ещё одно приложение? Дело-то в том, что в итоговой программе ничего лишнего не будет - всё выкинется само.

Цитата: Kogrom
На счёт условной компиляции - это юмор, наверное. Даже в C++ можно сделать с помощью make-файлов кучу версий с разными включениями, а не только Debug и Release (и в каждой версии выбрать - включать отладочную информацию или нет). В Python ещё гибче, так как можно на ходу выбирать, какие модули будем подключать.


Ну почему юмор? Конечно, кроме условной компиляции есть другие средства (в C# специальные классы Debug и Trace, атрибут Conditional), но суть в том, что с их помощью я вставляю отладочную информацию в программу, которая используется в одной из конфигураций (Debug или другая, их можно создать сколько угодно), а в релизе ничего этого не будет.

Так я не понял: можно ли в Python сделать так, чтобы в одной конфигурации тесты выполнялись, а в другой - выкидывались? Причём переключение с одной конфигурации на другую должно происходить в пару кликов мышкой или пару строк кода.

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
У меня в шарпе пихаются :). Зачем мне ещё одно приложение?


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

Цитата: koodeer
Так я не понял: можно ли в Python сделать так, чтобы в одной конфигурации тесты выполнялись, а в другой - выкидывались? Причём переключение с одной конфигурации на другую должно происходить в пару кликов мышкой или пару строк кода.



Кликом мышкой нельзя ни в одном языке :)
Кодом - пожалуйста. Например:

 
Код:
if TEST:
    import test_something
else:
    import something

В общем, как и в C++ почти.
3
28 января 2011 года
Green
4.8K / / 20.01.2000
Цитата: Kogrom
Для ответа на вопросы мне надо полный класс и описание его обязанности. Из того, что приведено можно пока составить только класс, который пытается собой заменить функцию типа:
float calcArithmeticMean(SomeType items)


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

33K
28 января 2011 года
hivewarrior
205 / / 16.11.2010
Цитата: koodeer

Но неопытных-то большинство! И нужно сделать так, чтобы их ошибки автоматически отлавливались компилятором.
Иначе эти ошибки джуниоров придётся отлавливать тим-лидам. Что дорого и нелогично.



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

Ошибки отлавливать надо, но не варнинги. Надо понять, что предупреждение - это, собственно, предупреждение. Рассмотреть его и уже выносить приговор: казнить или миловать. Но возводить ужасающие рамки тоже не вариант, ибо даже самый матерый программист будет плевать на все варнинги, если только 1% будет толковыми.

Пример нынешнего моего варнинга:



Вырастит качество, но за все надо платить. "Умная" среда или будет генерировать медленный/нестабильный код, или добавит еще какой половник дегтя.

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

Цитата: koodeer

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



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

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: Green
Это пример и в нем вполне достаточно данных для примера.



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

Зачем городить класс там, где можно обойтись методом, тем более что у него большой потенциал повторного использования? Велика вероятность, что и другим классам могут потребоваться функции calcArithmeticMean, calcSum. Более того, sum (accumulate) есть в стандартных библиотеках известных мне языков, что подтверждает мысль о повторном использовании.

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Продолжу развивать идею. Для этого подходят вопросы от уважаемого Green-а.
Цитата: Green
Честно говоря, мне даже не совсем понятно, как ты собираешься тотально вынести приватные методы в отдельный класс. А как же приватные данные? Они тоже перенесутся в этот вспомогательный класс?
И видимо этот "помощник" должен быть тотально пабликом?
Т.е. любой класс в реальности это будет два класса: этакий "интерфейс+" у которого интерфейс требуемого класса и часть реализации в паблик методах, причем как я понял никакого внутреннего состояния, т.к. все внутреннее состояние и реализация в другом "вспомогательном классе". Т.е. в реальности ВСЁ в вспомогательном классе, а основной класс - просто пустышка?


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

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

Цитата: Green
Только вот связанность этих классов получится на столько сильной, что практически нельзя будет изменить один класс не изменив другой. Аналогично и с тестами.


Не совсем так. Класс-помощник будет независим от главного. У него будет потенциал использования в другом классе.

Цитата: Green
Да нафиг такое тестирование, для которого надо так усложнять систему. Это введет только ещё больше вероятностей ошибок.


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

297
28 января 2011 года
koodeer
1.2K / / 02.05.2009
Цитата: Kogrom
Кликом мышкой нельзя ни в одном языке :)


Таки можно! Глянь картинко - выбор конфигурации кликом мышки :)
Я ж говорю - выкинь свою IDE, возьми нормальную :D
Перейди на нормальный язык со статической типизацией - это махом решит кучу проблем с тестами ;)

87
28 января 2011 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Таки можно! Глянь картинко - выбор конфигурации кликом мышки :)



koodeer, не заставляй меня усомниться в тебе и спутать с людьми, которые путают язык и IDE.

297
28 января 2011 года
koodeer
1.2K / / 02.05.2009
Ладно-ладно, Kogrom, не ругайся. Я понимаю, что в коде нужно добавить несколько строк.

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

Хотя ты же и на C++ пишешь. Не понимаю...
Продолжай дискуссию, авось что-то прояснится.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог