Хелперы vs множественное наследование
От: Khimik  
Дата: 03.03.19 15:57
Оценка:
Я уже давно спрашиваю на разных форумах про множественное наследование и интерфейсы в Delphi, и никто не до сих пор не объяснил на пальцах суть всего этого.
Вот пример задачи, для которой мне нужно множественное наследование. В Delphi есть класс TStream, и наследники TFileStream и TMemoryStream. Я хочу добавить ко всем этим стримам функции для более удобного чтения/записи конкретных типов данных: ReadBoolean, ReadInteger, ReadString, WriteBoolean, WriteInteger, WriteString и т.д. И тут начинаются проблему: я не могу добавить эти методы к классу TStream, а могу только к наследникам. Как мне добавить эти методы к разным типам стримов без дублирования кода?
Насколько я понял, для этого можно использовать интерфейсы, но я пока не знаю как конкретно это реализовать, и вообще в Delphi интерфейсы вроде привязаны к COM, у них у всех есть GUID, и это уже вызывает тоску.

Недавно я узнал про хелперы в Delphi:

http://asd-soft.ru/integer-helper-create/

А в других языках они есть? Я пока не начал это осваивать, но вроде понятен их смысл – можно прикрутить к любому типу, например, integer, какую-то функцию, например GetFactorial, и писать в коде fact1:=12.GetFactorial;
Очевидно, хелперы можно применить для моей задачи – прикрутить их напрямую к классу TStream. Но я слышал, что использование хелперов опасно, поскольку оно противоречит парадигме ООП. Хотелось бы узнать об этом подробнее.
Мне кажется, главная опасность использования хелперов с классами возникает там, где есть динамические функции. И я думаю, что для избегания этих проблем я буду делать так: все функции, реализованные через хелперы, будут иметь название, начинающееся с hf, например myfilestream1.hfWriteBoolean();
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re: Хелперы vs множественное наследование
От: sqrt  
Дата: 03.03.19 17:58
Оценка:
Здравствуйте, Khimik, Вы писали:


K>А в других языках они есть? Я пока не начал это осваивать, но вроде понятен их смысл – можно прикрутить к любому типу, например, integer, какую-то функцию, например GetFactorial, и писать в коде fact1:=12.GetFactorial;


В C# есть Extension Methods.

K>Очевидно, хелперы можно применить для моей задачи – прикрутить их напрямую к классу TStream. Но я слышал, что использование хелперов опасно, поскольку оно противоречит парадигме ООП. Хотелось бы узнать об этом подробнее.


В .NET на методах расширения LINQ сделан, польза там есть на лицо. Не думаю что в Delphi от хелперов есть какая-то опасность, хелперы не добавляют к классам/записям дополнительное состояние, хотя могут менять внутренее.

K>Мне кажется, главная опасность использования хелперов с классами возникает там, где есть динамические функции. И я думаю, что для избегания этих проблем я буду делать так: все функции, реализованные через хелперы, будут иметь название, начинающееся с hf, например myfilestream1.hfWriteBoolean();


Имхо, префиксы в названиях неинформативны и наоборот затрудняют понимание кода, да и в библиотеке Delphi к названиям методов/функций префиксы нигде не добавляются.
Re: Хелперы vs множественное наследование
От: Jack128  
Дата: 04.03.19 06:13
Оценка:
Здравствуйте, Khimik, Вы писали:

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

А в целом полно языков где подобные механизмы есть. В .NET экосистеме C#/VB.NET/F# , в Java — Kotlin/Groovy
Re[2]: Хелперы vs множественное наследование
От: Khimik  
Дата: 09.03.19 08:25
Оценка:
K>>Мне кажется, главная опасность использования хелперов с классами возникает там, где есть динамические функции. И я думаю, что для избегания этих проблем я буду делать так: все функции, реализованные через хелперы, будут иметь название, начинающееся с hf, например myfilestream1.hfWriteBoolean();

S>Имхо, префиксы в названиях неинформативны и наоборот затрудняют понимание кода, да и в библиотеке Delphi к названиям методов/функций префиксы нигде не добавляются.


С чего бы это?
Я наоборот скорее всего буду теперь очень активно использовать префиксы. Например, я практически никогда не использую секцию private у классов, поскольку на практике изредка оказывается таки нужно обратиться к полю или методу, который скрыт этой функцией. Поэтому лучше названия эти поля и методы объявлять в public, но названия начинать с префикса, например pr: MyIntegerArray.prDataChanged. Собственно обычно для полей, объявленных в private, используется префикс f, это тоже более-менее удобно.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re: Хелперы vs множественное наследование
От: vsb Казахстан  
Дата: 09.03.19 08:45
Оценка:
Extension method это просто другой синтаксис для записи утилитного метода, в который передаётся параметр this. Ты можешь написать класс IntegerUtil и вызывать его как IntegerUtil.GetFactorial(12). Ничего опасного или страшного в них нет. Просто надо понимать, что это т.н. синтаксический сахар, т.е. конструкция, которая тривиально преобразовывается в другую конструкцию и только выглядит как метод.
Re[3]: Хелперы vs множественное наследование
От: sqrt  
Дата: 09.03.19 13:28
Оценка:
Здравствуйте, Khimik, Вы писали:


K>>>Мне кажется, главная опасность использования хелперов с классами возникает там, где есть динамические функции. И я думаю, что для избегания этих проблем я буду делать так: все функции, реализованные через хелперы, будут иметь название, начинающееся с hf, например myfilestream1.hfWriteBoolean();


S>>Имхо, префиксы в названиях неинформативны и наоборот затрудняют понимание кода, да и в библиотеке Delphi к названиям методов/функций префиксы нигде не добавляются.


K>С чего бы это?

K>Я наоборот скорее всего буду теперь очень активно использовать префиксы. Например, я практически никогда не использую секцию private у классов, поскольку на практике изредка оказывается таки нужно обратиться к полю или методу, который скрыт этой функцией. Поэтому лучше названия эти поля и методы объявлять в public, но названия начинать с префикса, например pr: MyIntegerArray.prDataChanged. Собственно обычно для полей, объявленных в private, используется префикс f, это тоже более-менее удобно.

Я стараюсь придерживаюсь принсипов SOLID, а префиксы да, и в самом деле не важны, мне они лично не нраятся.
Re[3]: Хелперы vs множественное наследование
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.03.19 16:10
Оценка: +1
Здравствуйте, Khimik, Вы писали:

K>Я наоборот скорее всего буду теперь очень активно использовать префиксы. Например, я практически никогда не использую секцию private у классов, поскольку на практике изредка оказывается таки нужно обратиться к полю или методу, который скрыт этой функцией. Поэтому лучше названия эти поля и методы объявлять в public, но названия начинать с префикса, например pr: MyIntegerArray.prDataChanged. Собственно обычно для полей, объявленных в private, используется префикс f, это тоже более-менее удобно.


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

Вариант с раздельными префиксами для public/protected/private полей я постоянно "испытываю" в Python, такое же происходит в Go. IMO, недостатков больше, чем достоинств.
The God is real, unless declared integer.
Re[4]: Хелперы vs множественное наследование
От: Khimik  
Дата: 09.03.19 16:49
Оценка:
N>Для контролируемого обращения к приватным полям надо использовать сеттеры и геттеры, в которые можно внедриться, например, с отладкой (даже без изменения кода). А открывать их на общий доступ — всё равно будет где-то проскальзывать, что не заметили, что лезут в приватное поле, несмотря на суффикс.

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

N>Вариант с раздельными префиксами для public/protected/private полей я постоянно "испытываю" в Python, такое же происходит в Go. IMO, недостатков больше, чем достоинств.


А какие конкретно недостатки?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.