паттерны программирования
Jul. 5th, 2022 03:53 pmГлавная боль с ними - это отсутствие нормальной документации.
Я только что хотел показать человеку "adapter". Казалось бы, пять строчек. Всё, что я нашёл - это какая-то бездна, и мой мозг стекает ещё до того, как я заканчиваю читать. Я понимаю паттерн, я не понимаю, что эти авторы хотят сказать.
Или, фабрика. Тривиальная же вещь: верни функцию с замыканием вместо значения. Но нет, всё, что идёт в статьях со словом "pattern", кажется, написано людьми, которые *любят* xml, писают кипятком от синтаксиса java и хочень бы хотели xlst вот ту вот очаровательную soap.
... Отсюда, вопрос, а есть ли кто-то, кто этим вопросом занимался и кто бы написал вменяемый обзор? Я понимаю, что у разных языков программирования разный уровень бойлерплейта (builder pattern для Rust/Java - это база и так и надо, в питоне можно, но будет выглядеть странно, потому что в аргументах можно много и выразительно варьироваться), но всё-таки, самый базовый простой обзор? Желательно, без махрового ООП.
Я только что хотел показать человеку "adapter". Казалось бы, пять строчек. Всё, что я нашёл - это какая-то бездна, и мой мозг стекает ещё до того, как я заканчиваю читать. Я понимаю паттерн, я не понимаю, что эти авторы хотят сказать.
Или, фабрика. Тривиальная же вещь: верни функцию с замыканием вместо значения. Но нет, всё, что идёт в статьях со словом "pattern", кажется, написано людьми, которые *любят* xml, писают кипятком от синтаксиса java и хочень бы хотели xlst вот ту вот очаровательную soap.
... Отсюда, вопрос, а есть ли кто-то, кто этим вопросом занимался и кто бы написал вменяемый обзор? Я понимаю, что у разных языков программирования разный уровень бойлерплейта (builder pattern для Rust/Java - это база и так и надо, в питоне можно, но будет выглядеть странно, потому что в аргументах можно много и выразительно варьироваться), но всё-таки, самый базовый простой обзор? Желательно, без махрового ООП.
no subject
Date: 2022-07-05 02:11 pm (UTC)У меня было, но я и сайт закрыл уже давно. Вот, запостил.
no subject
Date: 2022-07-05 02:34 pm (UTC)Ну вот у тебя там "классы". А ведь паттерны никакого отношения к классам не имеют. Их можно использовать для классов, но, например, тот же builder прекрасно реализуется на структурах. Или "фабрика" (кстати, я не знаю, "фабрика" и "абстрактная фабрика" это одно и то же?)
no subject
Date: 2022-07-05 03:03 pm (UTC)Фабрика производит инстансы конкретного типа, а абстрактная параметризуется типом. Верно насчет классов. Но не редактировать же эту древнюю хрень.
no subject
Date: 2022-07-05 03:43 pm (UTC)Ну и вообще, по уму не люди для паттернов, а паттерны для людей. Не нужно писать программы "вот тут мы поставим такой паттерн, там - эдакий паттерн". Нужно писать программы "тут мы сделаем вот так, потому что оно следует из логики нужного - о, да это же получается паттерн Х, значит надо обратить внимание на то и это, типичное для такого паттерна".
Что не так с изначальной книжкой? (Ну, кроме того, что она не объясняет "паттерны для людей").
no subject
Date: 2022-07-06 08:45 am (UTC)А, "абстрактная" - это с типопараметром? Вероятнее всего, это заметно в языках с generic'ами и статической типизацией.
no subject
Date: 2022-07-06 08:47 am (UTC)Вот например:
http://www.cs.ox.ac.uk/publications/publication1452-abstract.html
no subject
Date: 2022-07-06 08:49 am (UTC)!markdown Вот пример типовой фабрики из питона:
Где здесь классы? (можно даже декоратор пропустить - просто
return inner_eval- вот тебе и фабрика). Для меня вот эта взаимосвязь "родительский класс и подкласс" совершенно не очевидна.Фабрика производит любые новые объекты. Это могут быть функции, модули, даже package'и. Могут быть инстансы класса, могут быть классы.
Изначальную книжку, кстати, надо прочитать, хотя я подозреваю, что оно всё будет утыкано "родительскими классами" и прочими оопными фигнями.
no subject
Date: 2022-07-06 08:52 am (UTC)Опять не туда.
Паттерн - это "приём". Характерное решение, которое легко считывается и про которое известно, что оно хорошо работает. Я могу с ходу десяток паттернов для ансибла написать, и ни один из них не связан с ООП или "higher order types".
То же касается и обычных паттернов программирования. Это приёмы, простые и ясные. Когда их закапывают в ООПшную генеалогию, они становятся такими же уродливыми, как и их генеалогия.
no subject
Date: 2022-07-06 09:24 am (UTC)Первый — это то, что GoF'овские крокозяблы продиктованы структурой языка (Java/C++) в значительной степени; сами паттерны (как типовые проблемы и типовые решения) от этого никуда не деваются и статья по ссылке как раз показывает как их выразить проще, вплоть до тривиальности.
Второй — Банда действительно много чего интересного обошла вниманием, но этого по-моему в связном виде очень и очень мало.
PS. И вдогонку:
Отсюда: https://sourcemaking.com/design_patterns/
Выделенное по-моему вполне объясняет почему "паттернами" никто не занимается за пределами OOA/OOD тусовки — за отсутствием предмета занятий.
no subject
Date: 2022-07-06 11:42 am (UTC)Нет, проще. Возвращаемая имплементация запрашиваемого интерфейса зависит от рантайм-факторов.
no subject
Date: 2022-07-06 11:43 am (UTC)Это максимализм, который говорит, что любое общечеловеческое характерное соглашение может быть описано в коде и переиспользовано.
Вот, например, есть паттерн, что если приложению не передали имя файла как аргумент, надо читать с stdin.
Это такой добротный паттерн, но я с трудом представляю себе это как универсальный код.
Или, например, есть такой паттерн: разделять приложение foo на libfoo и само foo, которое использует libfoo. И как они это собираются использовать посредством reference?
Они слишком узко интерпретируют понятие "паттерн". Некоторые паттерны служат для обхода кривизны языка (привет,
if __name__ == '__main__'), некоторые - всего лишь типовые решения типовых задач, которые часто выходят за пределы языка программирования и находятся на стыке технологий.(Паттерн разработки под докер - переменная среды окружения PORT задаёт имя порта на котором слушать).
no subject
Date: 2022-07-06 12:27 pm (UTC)> приложению не передали имя файла как аргумент, надо читать с stdin.
Как фича application framework'а например.
> разделять приложение foo на libfoo и само foo, которое использует libfoo.
Как фича системы сборки, которая определяет, например, собираемся ли мы под условный дебиан и включает это разделение. Вопрос лишь в том, нужны ли нам настолько умные фреймворки.
no subject
Date: 2022-07-06 12:32 pm (UTC)Ну то есть я хочу сказать, что утверждение, что "существование паттерна - это наша недоработка", это чрезмерный максимализм.
Хотя бы потому, что паттерны приходят и уходят по мере обнаружения, что они не решают какой-то (другой) класс вопросов.
Например, был паттерн garbage in garbage out, а сейчас это фу-фу-фу и так делать не надо. Просто так перестали писать. В старом коде это осталось. Если бы это было кодифицровано в инструменте, то было бы очень больно всё менять.
Короче, паттерны разработки - вполне себе разумное понятие и знание их тоже разумно. Если кто-то хочет часть паттернов утащить на уровень языка (например, тот же Питон в себя всосал и "decorator", и "builder"), то ура, ура. Но это не отменяет самой концепции и пользы разумного (не перегруженного оопшностью) каталога оных.
no subject
Date: 2022-07-06 12:45 pm (UTC)Вообще, это звучит как "плагин" или даже dyn trait, а не как фабрика.
no subject
Date: 2022-07-06 01:10 pm (UTC)no subject
Date: 2022-07-06 01:11 pm (UTC)Для меня это паттерн (ок, анти-паттерн) разработки. Я его могу идентифицировать и либо ему следовать, либо с ним бороться.
no subject
Date: 2022-07-07 12:08 am (UTC)Классическая фабрика - именно виртуальный конструктор.
no subject
Date: 2022-07-07 09:17 am (UTC)Для меня это новость, например. Сколько я работал - фабрика, это то, что возвращает callable. Точнее, "фабрика", это паттерн, в котором нам надо сделать "значение с параметром", и для "значения с параметром" мы возвращаем callable, в котороый это значение уже и передаётся.
Возможно, это эффект питоновой пофигистичности в вопросах обязательности классов, но мне кажется, что для объяснения сути происходящего классовость как раз второстепенна.
Кстати, функция может возвращать класс. Я так даже иногда делаю.
(или return Resut(), не важно)
Очень удобно потом делать foo().foo или foo().bar
Интересно, это всё-таки уже фабрика или нет?
no subject
Date: 2022-07-07 04:44 pm (UTC)Но это непростые примеры. Для них функции и классы должны быть нетривиальными, поддерживающими объектный интерфейс. Чтобы посмотреть, как выглядит внутри функция-как-объект, посмотрите на функторы в C++. Вкратце, их интерфейс заключается в наличии перегруженного оператора () с некоей ожидаемой сигнатурой (как это нынче называется по-русски?). Точно так же, класс-как-объект можно описать как имеющий интерфейс в виде функции (или нескольких функций с разными аргументами), которая конструирует объекты - угу, виртуальный конструктор. То есть, этот класс является по сути фабрикой (ну да, фабрика в фабрике). Ну, плюс можно конечно добавить некие "статические методы", но потребность в фабрикации классов - не в них, а в "фабрике в фабрике".
Все это гораздо сложнее и запутаннее для объяснения, чем классический вариант. И понимание этих сложных вариантов требует сначала понимания простого классического варианта (что, наверное, эта дискуссия тоже демонстрирует).
Возврат callable - это вообще ситуация, где можно легко обойтись без фабрик. Можно просто вместо фабрики передавать функцию, которая будет каждый раз вызываться с полным набором параметров. Фабрика тут дает оптимизацию, когда некое повторно используемое подмножество параметров можно пред-обработать один раз и потом запомнить в обработанном виде для последующих вызовов.