ООП и Ардуино

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
@Boroda22, в большинстве случаев нет понимания сути ООП, всё ограничивается инкапсуляцией какой-то сущности в класс, и на этом все заканчивается.
 

poty

★★★★★★✩
19 Фев 2020
3,005
898
@Kir, Недавно начали читать умные книги? :)
Послушайте, если "проектировщик" не может справиться с десятком простых методов, сможет ли он разработать интерфейс? А разделить событие и обработку?
 

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
@poty, мне кажется уже где-то отвечал на подобный вопрос.
ООП же подразумевает декомпозицию конечной задачи. Это не такая простая задача, как может показаться на первый взгляд, тут нужна практика, книжки, безусловно, помогают, чтобы проектировать удачные интерфейсы, которые можно было бы и в дальнейшем использовать, но инструкции как эту декомпозицию делать не дают, максимум - рекомендации. Самая распространённые книги по использованию ООП - "Приёмы объектно-ориентированного проектирования" банды четырёх (GoF), книги Роберта Мартина (принципы SOLID).
Кроме того, проектирование через интерфейсы - это использование полиморфизма, а без полиморфизма как такового ООП нет. Если посмотреть реализации всяких библиотек, для ардуино в частности, то там полиморфизм крайне редко используется. Основным аргументом против - типа жрет память, ну да, жрет - указатель на таблицу виртуальных функций, для AVR это 2 байта вроде. Другая причина, как я уже писал выше, кода приходится писать больше, иногда сильно больше. Ещё можно услышать что-то вроде:
  • "...я не профи, это мое хобби, мне это нафиг не нужно..."
  • "...это все для "взрослых" компьютеров, для МК это все слишком избыточно..." - практика показывает, что все норм и на МК, если знаешь что делаешь.
  • "...вызов виртуального метода - это "дорогая" операция..." - речь о нескольких дополнительных инструкциях, т.е. речь идет о единицах нс., самое забавное, что полиморфный код работает, порой, даже быстрее, чем классический императивный подход.
 
  • Лойс +1
Реакции: Boroda22

bort707

★★★★★★✩
21 Сен 2020
2,911
865
Если посмотреть реализации всяких библиотек, для ардуино в частности, то там полиморфизм крайне редко используется.

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

И насчет "редко используется" - вы не правы. в серьезных больших проектах полиморфизм а ардуино встречается постоянно. Как пример - библиотека FastLED. Или Adafruit_GFX
А то что его нет в мелких проектах, типа библиотеки на один конкретный сенсор - ну так зачем там полиморфизм, если уровень абстракции единственный?
 

poty

★★★★★★✩
19 Фев 2020
3,005
898
@Kir, истинный полиморфизм возможен только в скриптовых языках, которые в ограниченной памяти микропроцессора не применить из-за необходимости тянуть библиотеку времени выполнения, сильно избыточную за счёт функций, которые в данной конкретной реализации не используются. Ну, я уже не говорю о возможности реалтайм обработки в условиях отсутствия механизмов многозадачности на аппаратном уровне (то есть, интерпретация кода поставит крест на выполнении, собственно, алгоритма и все эти "передачи сообщений" будут бесполезны, так как всё равно где-то в коде нужно будет явно вызывать обработчик этого сообщения в другом классе). Если применять множество функций для реализации одного и того же с разным типом данных, то в С++ это работает, но ограниченно. И превращается всё это дело в необходимости выделять память в каждом инстансе под каждый тип данных. Это снова память, и немалая.
Сразу оговорюсь, что динамическое выделение памяти без реального менеджера памяти/сборщика мусора (нет ОС - нет менеджера) - это путь в непрогнозируемое выполнение.
Что касается накладных расходов: любой класс, имеющий несколько инстансов, накладывает необходимость передачи в каждый вызов функции неявного указателя *this, а это уже не два байта, если метод, конечно, не один. Т.е., код-то переиспользуется, но шлейф информации о конкретном устройстве вызвавшего класса добавляется в любом случае.
 

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
для полиморфизма? не путаете? :)
Полиморфизм, он же вроде позволяет создавать новые обьекты , максимально используя уже имеющийся код, нет? :) То есть кода меньше, а не больше.
Полиморфизм позволяет "спрятать" за интерфейсом абстракции множество разных реализаций.
т.е. если в лоб сравнить код одной и той же задачи, с применением всей этих абстракций и без, то общее количество кода с использование абстракций скорее всего будет больше, но тут конечно зависит от задачи, и конкретной реализации.
Когда имеется база уже наработанных компонентов, и переиспользуется скажем процентов 70, то конечно, все проще становится. И опять же, далеко не факт, зависит от того как спроектированы интерфейсы и реализованы компоненты.

И насчет "редко используется" - вы не правы. в серьезных больших проектах полиморфизм а ардуино встречается постоянно. Как пример - библиотека FastLED. Или Adafruit_GFX
Серьезный проект - тут довольно много субъективного восприятия, я лишь озвучил статистику, которую наблюдаю просматривая embedded проекты, для ардуино в частности, возможно мне попадаются не правильные проекты)))

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

Я же не агитирую никого делать все на ООП, спросили почему мало кто использует, я привел свои тезисы, который перекликается с вашим: "...ну так зачем там полиморфизм...".
 
  • Лойс +1
Реакции: Boroda22

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
@poty, все сейчас смешалось, поток разной, не обузданной информации.
Не понятно, причем тут скриптовые языки, и что такое истинный полиморфизм, я, например, не знаю, что такое истинный полиморфизм, увы), но звучит как что-то сакральное.

@Kir, Сразу оговорюсь, что динамическое выделение памяти без реального менеджера памяти/сборщика мусора (нет ОС - нет менеджера) - это путь в непрогнозируемое выполнение.
Все вполне прогнозируемо, но, если не хотите использовать динамическую память, выделяйте статически, тем более, что очень часто заранее известно, какие экземпляры будут в работе. Но, если необходимо подменять экземпляры во время выполнения, то создание всех возможных экземпляров заранее, конечно, может дорого стоить, но и тут есть пути решения.

@Kir, Что касается накладных расходов: любой класс, имеющий несколько инстансов, накладывает необходимость передачи в каждый вызов функции неявного указателя *this, а это уже не два байта, если метод, конечно, не один. Т.е., код-то переиспользуется, но шлейф информации о конкретном устройстве вызвавшего класса добавляется в любом случае.
Ну так работает связывание данных и поведения, а как вы предлагаете это реализовывать? Если вы просто создадите структуру, и передадите указатель на её экземпляр в функцию, будет же ровно тоже самое, в чем тут накладные расходы? Тут "дешевле" сделать не получится. Можно конечно и захардкодить, так сказать прибить гвоздями, но сами понимаете, что такой код практически не переиспользуемый, и то, ислючительно copy-paste.
 

poty

★★★★★★✩
19 Фев 2020
3,005
898
@Kir, проще, наверное, почитать. ООП - это не только, и даже не столько полиморфизм, не стоит сводить всё к нему. Реализация в С++ предполагает, что типы данных будут известны на этапе компиляции и, соответственно, "гвоздями прибиты" как в реализации (нужно для каждого типа и вида написать свой обработчик), так и в использовании (результат может быть присвоен переменной только определенного типа).
Элементы полиморфизма присутствуют даже в той библиотеке, что использует ТС: возможна обработка как "цифровых клавиатур", так и "аналоговых" одинаковыми методами. Только ТС даже в таком виде не стал с этим разбираться, а просто решил, что библиотека плохая, раз ещё и самому к ней код нужно писать. Типичный подход, скажем прямо.
И, скажите начистоту, зачем для обработки одной команды чтения регистра Вам нужен полиморфизм? Да и ООП? Упоминаемая библиотека создана для тех, кому простейшая логика кажется неподьемной. Выясняется, что даже это свойство "сокрытия логики" не помогает, когда отсутствует логика работы кода, написанного извне. Поэтому аргумент, что здесь бы помог полиморфизм (ООП, интерфейсы, ...) - это в пользу раздувания кода из ничего. И именно поэтому часто код на С значительно более управляемый в таких применениях, чем ООП, не говоря о том, что существенно более быстрый и короткий.
 

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
@Kir, проще, наверное, почитать. ООП - это не только, и даже не столько полиморфизм, не стоит сводить всё к нему.
Не только, но вся сила и мощь, если угодно, ООП раскрывается именно в полиморфизме. А чисто технически в С++, для реализации полиморфизма, необходимо использовать и инкапсуляцию, и наследование.

@Kir, Реализация в С++ предполагает, что типы данных будут известны на этапе компиляции и, соответственно, "гвоздями прибиты" как в реализации (нужно для каждого типа и вида написать свой обработчик), так и в использовании (результат может быть присвоен переменной только определенного типа).
Да, потому, что язык статически типизированный, как и C#, и Java.

@Kir, Элементы полиморфизма присутствуют даже в той библиотеке, что использует ТС: возможна обработка как "цифровых клавиатур", так и "аналоговых" одинаковыми методами. Только ТС даже в таком виде не стал с этим разбираться, а просто решил, что библиотека плохая, раз ещё и самому к ней код нужно писать. Типичный подход, скажем прямо.
Что это за элементы полиморфизма, он либо есть, либо его нет, а его там нет. ТС тут вообще ни при чем, дискуссия об ООП и полиморфизме началась иначе.

@Kir, И, скажите начистоту, зачем для обработки одной команды чтения регистра Вам нужен полиморфизм? Да и ООП?
Вот об этом я и говорю, что нет понимания сути. Зачем оно вообще нужно, если можно и без него все сделать?
Суть приемов ООП в том, чтобы проще было управлять осями изменений. Ось изменений это место, где может проходит какое-то изменение, как ни странно)))
Пример, немного утрированный, но вполне возможный в реальности: у вас проект, в котором используется gpio для вывода какой-то информации. Сделали, все работает, замечательно. Но потом выясняется, что нужно добавить функционал, но для этого необходимо освободить пины (ШИМ например понадобился, или интерфейс какой, не суть важно), которые уже заняты, а в качестве компенсации использовать расширитель портов, решили, что это будут сдвиговые регистры. Скорее всего вам придется придется переписать уже отлаженную программу, что может её сломать, и потом снова придется отлаживать. а потом может оказаться, что придется поменять сдвиговый регистр на расширитель портов по i2c, так как SPI нужен в другом месте, что вас ждет - переписывание программы в 3-й раз.
Что нам могут дать приемы ООП, создать абстракцию (интерфейс) для gpio, и несколько реализаций: обычный порт, сдвиговый регистр, расширитель портов по i2c. Основная логика программы не знает о реализации, так как работает с абстрактным интерфейсом, и когда придется поменять работу с портом, не нужно переписывать уже отлаженную основную программу, достаточно просто сделать нужную реализацию, если её ещё нет. Так же это хорошо сработает, если вам необходимо переехать на другой МК, достаточно переделать реализации интерфейсов, а код основной программы не изменяется, кроме всего прочего улучшится читаемость основной программы, за счет удаления из неё деталей реализации gpio,
Другой пример, который касается конкретно полиморфизма. Часто наверное приходилось сталкиваться с лестницами из операторов ветвления, опять же, нужно добавить что-то, это ещё один else if. Если их много, и код в составных операторах объемный и не простой, наверное тут лучше использовать полиморфизм, читаться будет в разы лучше, а если придется что-то добавить или поправить, то не придется лезть в основную программу. Почему так происходит, потому что происходит инверсия зависимости, так как основная программа перестает зависеть от конкретной реализации, а конкретная реализация зависит от интерфейса, который использует основная программа.

@Kir, Упоминаемая библиотека создана для тех, кому простейшая логика кажется неподьемной. Выясняется, что даже это свойство "сокрытия логики" не помогает, когда отсутствует логика работы кода, написанного извне. Поэтому аргумент, что здесь бы помог полиморфизм (ООП, интерфейсы, ...) - это в пользу раздувания кода из ничего. И именно поэтому часто код на С значительно более управляемый в таких применениях, чем ООП, не говоря о том, что существенно более быстрый и короткий.
Никто не говорит, что полиморфизм тут прямо необходим, и без него тут делать нечего, был задан вопрос, а возможно ли так, да возможно, а почему никто так не делает, далее я привел свои доводы почему.
Никто никого не заставляет все делать с использованием ООП. ООП это концепция, её либо используют, либо не используют. Если используют получает один код, если не используют, получается другой код. Использование/не использование не означает хорошо/плохо. Плохим или хорошим может быть проектирование и реализация, и не важно какая выбрана концепция.