LINUX.ORG.RU
ФорумTalks

Почему боятся ООП?

 


0

6

Заметил, что некоторые разрабы стесняются (триггерятся/истерят/брезгуют/отстраняются/впадают_в_кому от) ООП. Почему? Вот, один говорит «у нас тут не наследование, а …», так и хочется добавить «розовые пони». Т.е. если ты можешь реализовывать интерфейсы, у тебя уже нет отношения is-a? Может быть, какие-то древние ЯП не поддерживали чисто виртуальные интерфейсы, и нужен был непременно базовый класс, но как минимум уже C++ сломал эту традицию.

★★★★★

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

наследование реализации вполне можно декорацией замещать

более того мало где в наследовании используется «ante_super»

т.е обращение в родительской реализации к уточнённой(если есть) реализации в непосредственном потомке в котором вот это вот всё

вообще забавно как здравая идея расширения вложенных вызовов процедур Алгола обобщая own локальные переменные - породило современные изводы ООП-сект

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

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

а по красоте есть метод произвдения классов - в «более чистых» языках нет проблем сообщать что функция есть метод на классе декартово произвдени от вот этих вот перечисленных классов

и для случая когда перечисление из двух и семантике не важен порядок

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

но поезд APL и J и К явно уже давно не сейчас

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

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

да это же сугубо терминологические трудности. И не трудности вовсе. Какая разница, назовете вы некий неймспейс модулем, и будете импортировать из модуля «независимую» функцию (а на самом деле она никакая не независимая) или назовете его классом и будете использовать статический метод класса? В первом случае у вас имя функции разрезолвится во что-то типа «com.vasia.pet_project.helpers.mySuperFunction» во втором «com.vasia.pet_project.helpers.Helpers.mySuperMethod». Вот о чем здесь трагедию устраивать?

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

мне по сути ни какой

ТС ни какой (как я это понимаю)

некотором же сторонникам единственно-правильного ООП - это же важнейшее «иголье ушко» отличающее райское наслаждения райского ООП от мерзости отринувших_по_малоумию_истиныОпепе

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

Импортируйте статическую функцию и вызывайте с двумя аргументами.

То есть вместо ООП использовать обычный модуль. Выше с этого и началось. Что всё полезное в ООП возможно без ООП.

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

Есть формат документа страндартный для всех принтеров

Не работает так. Есть принтеры, умеющие (аппаратно) печатать штрихкоды. Есть принтеры с разным количеством красок. Будешь в универсальном формате писать все возможные варианты?

для настоящих физических принтеров это примерно так и устроено

Мне в LaTeX даже при формировании PDF уже приходится указывать, для какого принтера я его готовлю. Иначе значительная потеря качества.

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

наследование реализации вполне можно декорацией замещать

Это как?

Вот есть функция, ожидающая некий Button. Я написал свою реализацию кнопки MyButton. Как декорация позволит мне завернуть мою реализацию в ожидаемый тип?

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

идёт процесс приданию семантики высказанному синтаксическому комку...

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

Наследование реализации просто удобно.

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

копируешь весь код той кнопки.

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

zurg
()
Последнее исправление: zurg (всего исправлений: 1)
Ответ на: комментарий от monk

Тогда почему Ваш пример был с нетипизированными?

вероятно, потому что вы не знаете, как работает питон и вам не ведемо, что любой объект питона наследует базовый класс Object и соответвующие методы, которые и используют «нетипизированные функции» getattr и setattr?

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

Не работает так. Есть принтеры, умеющие (аппаратно) печатать штрихкоды. Есть принтеры с разным количеством красок. Будешь в универсальном формате писать все возможные варианты?

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

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

То есть вместо ООП использовать обычный модуль.

И чо?

Что всё полезное в ООП возможно без ООП.

разумеется, в машинных кодах нет никакого ООП. Вы спорите с собственными шумами в голове

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

появились способы обобщения кода без фундаментального косяка наследования

И какие же? Если нельзя трогать код библиотеки и разработчик не предоставил включения для передачи произвольной функции?

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

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

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

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

функция принт ни в каком бойлерплейте не нуждается

Да. Бойлерплейт всегда синтаксический мусор.

вы пришли к выводу, что стандартизировать операцию принт() невозможно и поэтому… достаточно функции принт из стд. Логику я потерял.

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

(defmethod print ((printer PDF) (document label)) ...)

(defmethod print ((printer PDF) (document invoice)) ...)

(defmethod print ((printer Barcode) (document label)) ...)

(defmethod print ((printer PDF) document) ...) ;

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

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

Ей можно передать любой объект, потому что любой объект наследует Object, а следовательно реализует __getattr__ и __setattr__

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

Поэтому там наследование фактически не требуется.

??? Это какой-то цирк с конями, честное слово.

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

как вы из этого сделали следущий вывод?

Вот мой пример c кнопкой.

Если у меня некий

class Panel 
{
   ...
   void add_button(Button btn);
   ...
}

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

А если в питоне

class Panel:
    ...
    def add_button(btn):
       ...
       btn.paint(...)
       ...
    ...

то мне наследоваться не обязательно. Достаточно реализовать все используемые в функции методы. В 1С так: наследования вообще нет, остальное ООП есть.

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

у питона хорошая дока ( да даже туториал отличный)

а ещё Ромальо книжка ух.

в пипхоне умена резолвятся в момент резолва в байткоде - поэтому достаточно уткотипности - т.е наличия подходящего имени в обьекте(классе а далее mro и да тут общей object последняя инстанция)

на этом и работает + у строк друг с другом и других обьектов ибо ктотама есть __add__

То что оне все от object не суть

qulinxao3
()
Последнее исправление: qulinxao3 (всего исправлений: 1)
Ответ на: комментарий от monk

А принтеру надо знать, как печатать все виды документов?

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

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

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

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 1)
Ответ на: комментарий от foror

для печати каждого типа документа нужно создать класс

Вот за это и не люблю ООП в стиле Явы. Вместо одного print, возможно, с табличкой диспетчеризации, получается вагон классов, как у Бориса в задаче про хлеб.

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

Для меня таковым является CLOS. Именно потому, что сначала я просто пишу функцию print. Если потом обнаруживаю, что по какому-то классу аргумента разное поведение, превращаю её в обобщённую функцию. Если выясняется, что на разные комбинации типов разный код, добавляют диспетчеризацию по второму параметру. Могу добавить код, который выполняется до или после для какой-либо подсветки классов.

И при всём при этом в клиентской части остаётся просто print(printer, document), а не приходится творить что-то вроде

printer.print(document.prepare(printer.getDataFor(document)))
monk ★★★★★
()
Ответ на: комментарий от monk

Вместо одного print, возможно, с табличкой диспетчеризации, получается вагон классов

Вы никуда не денетесь от вагона классов или вагона функций если у вас разные типы документов и разные типы принтеров. Потому что, вам для каждого отношения тип-документа::тип-принтера нужно будет запилить реализацию. 3 типа документа и 3 типа принтера? Получите и распишитесь 9 реализаций. Будет это 9 классов или 9 модулей с функциями неважно.

превращаю её в обобщённую функцию

В джаве делается также.

диспетчеризацию по второму параметру

В джаве можно и это сделать. Но обычно полиморфизм решает такую задачу.

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

То есть всё равно будут функции и этот аргумент не работает

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

И без ООП тоже никто не мешает сложить структуру и функции для работы с ней в один модуль.

Можно, но у вас сложность кода будет выше. Функции будут иметь больше аргументов, чем если их отрефакторить в классы с методами. Будет тяжелее понять как функции и структуры связаны друг с другом. Потому что, в классе методы и поля класса отражают его сущность и поведение. В модуль же обычно пихают всё подряд относящееся к теме модуля. Состояние в глобальные переменные, которые также нужно как-то увязать к чему оно относится, какие функции над ним могут работать.

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 1)
Ответ на: комментарий от foror

Там где не нужны классы обходишься структурами и функциями. Там где нужны классы используешь классы.

Согласен.

Функции будут иметь больше аргументов, чем если их отрефакторить в классы с методами.

obj.meth(arg1, arg2, ...) против meth(obj, arg1, arg2, ....). Одно и то же.

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

Так наоборот же. Функции, которые относятся к классу-структуре рядом, а не непонятно где, если они вдруг функции, а не методы.

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

Вы никуда не денетесь от вагона классов или вагона функций если у вас разные типы документов и разные типы принтеров.

before_print();
switch(document.typeid) 
{
  case INVOICE: ...
  case LABEL: 
    switch(printer.typeid)
    {

    }
  case ...
}
if(printer.typeid != PDF) { ... }
after_print();
monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от foror

3 типа документа и 3 типа принтера? Получите и распишитесь 9 реализаций. Будет это 9 классов или 9 модулей с функциями неважно.

Для этого придумали паттерн мост. И 9 превратится в 6.

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

Не превратится. Каждый принтер имеет свою систему кодов для драйвера. Один gcode, другой postscript и т.д. Каждый тип документа имеет свою структуру хранения. Один векторный, а другой битмап. Вектор нужно преобразовать в систему кодов драйвера. У нас 3 системы кодов драйвера. Значит будет 3 реализации для векторного документа. Для битмапа ещё 3 реализации. И т.д. Итого 3 типа - 3 типа принтеров -> 9 реализаций.

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

obj.meth(arg1, arg2, …) против meth(obj, arg1, arg2, ….). Одно и то же.

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

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 2)
Ответ на: комментарий от foror

Это детали принтера. У тебя должен быть промежуточный формат. Любой тип документа преобразуется в промежуточный формат. Промежуточный формат преобразуется в формат конкретного принтера, классом этого принтера. 6 классов.

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

то мне наследоваться не обязательно. Достаточно реализовать все используемые в функции методы.

ага, ага, если только в твоем графическом тулките нет чего-нибудь такого

match Component:
   case TextView(text):
      ...
   case Button(caption):
      ...
   case CheckBox(state):
      ...

а оно там есть. Ну и еще лучше так как вы нафантазировали в питоне не делать, а то может кровь из носа пойти

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

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

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

для печати каждого типа документа нужно создать класс

не стоит плодить абстракции, а делать все как можно минималистичнее

Неукоснительное соблюдение взаимоисключающих параграфов как оно есть. Впрочем, у адептов ООП всегда так — начинают за здравие, а буквально через пять минут начинается грёбаный чад кутежа с помощью паттерна Visitor.

Минималистичнее — это полиморфная функция (мультиметод) с множественной диспетчеризацией. Для каждого набора аргументов можно задать свою реализацию, причём в полном соответствии с Open-Closed Principle (который O в SOLID). И никакие новые классы не нужны, вообще совсем.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от foror

А потом к тебе приходят с заданием добавить ещё два типа документов и два принтера и твои 9 классов превратятся в 25. Сложность очень быстро растёт. В то время как в мосте рост линейный. Это всё упирается в планирование: делать надолго или херак херак мультиметод и в продаксьён.

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

Минималистичнее — это полиморфная функция (мультиметод) с множественной диспетчеризацией.

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

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

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

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

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

А потом к тебе приходят с заданием добавить ещё два типа документов и два принтера и твои 9 классов превратятся в 25

А тут всё по ситуации. Если сообщество активно и каждый поддерживает свой принтер, то проблем не будет - запилят за неделю 25 классов. Это хорошо параллелится. А вот создавать новый универсальный промежуточный формат может быть гемороем и оно не так хорошо параллелится. Одно дело запилить пару новых реализаций по тому, в чём ты отлично разбираешься. И другое дело изучать очередной гениальный формат и прогибаться под его ограничения и недоработки.

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 1)
Ответ на: комментарий от foror

Можно, но у вас сложность кода будет выше.

Ну-ну.

Функции будут иметь больше аргументов, чем если их отрефакторить в классы с методами.

Количество аргументов — это ещё не сложность, это только полсложности. Особенно если функции чистые — всё известно статически, без запуска программы на реальном вычислителе или моделирования её поведения в голове. Вот аргументы, если они такие — всегда то, если этакие — всегда это. Понятно даже котику.

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

А ещё методы одного класса могут вызывать методы других классов — и изменения в их состоянии тебе придётся учитывать тоже. Чуешь простоту несказанную? %)

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от Nervous

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

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

ты также поимеешь огромный геморой с состояними в своей процедурной архитектуре

Я? Нет. Обо мне уже дядя Рич позаботился, да не разгладятся никогда его кудри %)

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

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

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

Свои хелловорды можешь хоть на брайнфаке писать

Кложа не нравится — давай возьмём жопаскрипт. Жопаскрипт для тебя достаточно массовый? Есть в нём такая штука — Redux, предназначена примерно для того же, для чего и ссылочные типы в кложе — для управления состоянием.

И что ты думаешь? Без единого класса! Разве не чудо? %)

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

Либо создавать дополнительные структуры для состояний.

В моём примере первый аргумент obj и есть такая структура.

Но по сути вы здесь уже начинаете эмулировать ООП. Так может сразу юзать ООП, не?

Функция гибче. В ней состояние может быть не только в первом аргументе.

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

а оно там есть.

Это жуткое нарушение инкапсуляции, вообще-то.

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

Любой тип документа преобразуется в промежуточный формат.

Придумай промежуточный формат, который без потерь преобразуется из/в SVG, PNG, PSD, PDF, например. Писать в него вектор + растр + все спецпредставления, существующие хотя бы в одном из принтеров?

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

Redux

Частный случай ООП:

store.dispatch({ type: 'INCREMENT' }); // Увеличиваем значение на 1
console.log(store.getState()); // Выводит: 1

store.dispatch({ type: 'DECREMENT' }); // Уменьшаем значение на 1
console.log(store.getState()); // Выводит: 0

Что видим? Видим объекты, видим методы. Ты уверен, что это без классов? Или если ты не увидел class, то значит и не ООП тут, да?

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

Жопаскрипт для тебя достаточно массовый?

Опять путаешь тёплоё с мягким.

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 2)
Ответ на: комментарий от foror

Либо начнёшь изобретать ООП создавая состояния в структурах.

Ещё бывают, как минимум, состояния в таблицах. SQL плохо отображается на ООП, но эффективно работает.

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

состояния в таблицах

Так чтобы с этими состояними эффективно работать нужная целая СУБД и язык запросов SQL. Работают такие состояния на порядки медленне состояний на переменных или структурах. Так что мимо.

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

PostScript

В 1998 году Adobe ввела новый стандарт PostScript 3. Изменения по сравнению с Level 2 незначительны. Это можно понять, учитывая, что множество приложений до сих пор не может обеспечить полную поддержку PostScript Level 2. Основные преимущества PostScript 3:
PostScript — полнофункциональный тьюринг-полный язык программирования. Хотя программы на PostScript и создаются в основном не людьми, а другими программами, в принципе ничто не мешает писать на нём программы

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

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 1)
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)