Здравствуйте, Sinix, Вы писали:
I>>Это GOF-паттерны в пересказе от XopoSHiy. Рассуждения применимы исключительно к GOF и ни к чему более, а между тем паттерны есть вообще везде. S>Тогда паттерны у тебя вырождаются в баззворд, который не несёт никакой нагрузки.
Наоборот. Если ты не заметил, то паттерны GOF уже давно превратились в баззворды безо всякого смысла. За упоминание паттернов скоро лицо будут бить.
>Т.к. он может обозначать и типовые проблемы, как в GoF/Фаулере, и инструмент для решения проблем (как у Nuseraro), и рекомендации по проектированию API (как в FDG).
Я бы не ставил паттерны GOF вместе с паттернами у Файлера. Фаулер с Кентом Беком частенько стебутся с GOF.
S>Если в таком ключе обсуждать, у нас вообще дикая путаница выйдет.
Путаница уже давно и именно из за подхода GOF.
I>>На самом деле типовую проблему можно решить десятком разных способов и каждое решение будет типовым. С тз GOF не ясно, не то один паттерн, не то десять разных. S>По-моему (тут я согласен с XopoSHiy), неясность возникает если читать GoF как готовый решебник.
А он и есть решебник. При чем решение дается сходу, там где Intent, и там где диаграма. А проблема ставится неявно в простынях текста и кода.
Вот state
"Allow an object to alter its behavior when its internal state changes. The object will appear to change its class"
Это решение в чистом виде. Теперь посмотри Джошуа Кериевски, чего он пишет про State.
Вот strategy
"Define a family of algorithms, encapsulate each one, and make them interchangeable.
Strategy lets the algorithm vary independently from clients that use it. "
И снова — решение в чистом виде.
Decorator
Attach additional responsibilities to an object dynamically. Decorators provide
a flexible alternative to subclassing for extending functionality
Опаньки — и здесь решение.
>А если смотреть на описание проблемы (кстати это первый пункт в описании каждого паттерна), то становится понятно, что неоднозначность не в самой книжке, а в том, с какой стороны мы смортрим на проблему.
В GOF описание проблемы подается невнятно, многословно и на конкретных примерах. Описание паттерна это сходу решение, еще до постановки проблемы.
I>>ВОт берем например книгу Фаулера про DSL и видим, что один и тот же пример идет почти через всю книгу. Опаньки, сразу ясно, что надо выбирать тот, который лучше подходит в конкретной ситуации. S>Не читал но осуждаю, судя по оглавлению и превью — там вообще про классические паттерны речь не идёт, один-в-один пересказ dragon book с упором на особенности DSL.
Нет никаких "классических" паттернов. Все паттерны относятся к конкретным областям. Это может быть и кодирование, и АПИ, и внутренний дизайн и архитектура и все что угодно.
DSL это не пересказ dragon book, это навроде антологии вычислительных моделей. Из книги дракона только одна или две главы.
Здравствуйте, Ikemefula, Вы писали:
I>Наоборот. Если ты не заметил, то паттерны GOF уже давно превратились в баззворды безо всякого смысла. За упоминание паттернов скоро лицо будут бить.
И XopoSHiy как раз привёл логичное обоснование, почему оно так вышло. Не, конечно остаётся ещё версия "GoF изначально является бесполезной фигнёй, раскрученной на волне хайпа", но тогда и обсуждать нечего. Фигня — она и есть фигня
I>А он и есть решебник. При чем решение дается сходу, там где Intent, и там где диаграма. А проблема ставится неявно в простынях текста и кода. I>В GOF описание проблемы подается невнятно, многословно и на конкретных примерах. Описание паттерна это сходу решение, еще до постановки проблемы.
Тут согласен. С такой точки зрения я неправ и разницы действительно никакой.
I>DSL это не пересказ dragon book, это навроде антологии вычислительных моделей. Из книги дракона только одна или две главы.
Ок, спасиб!
Может я сути не понял, но я выложил справочник которым пользовался для того, что бы быстро въехать в тему по определенному шаблону проектирования.
Это не мое автороство. Но знаю точно, что много скопипастено с вики.
S>Неа, тут та же путаница: рефакторинг — это общее описание проблемы ("фиговый код, нужно улучшить"). Замена стратегии на Func/Action — это конкрентый инструмент.
Но эту проблему можно решить самыми различными способами: дописать комментариев, написать внешнюю документацию, переписать код.
Рефакторинг — проблема тяжелого к редактированию/поддержке кода + решение в виде улучшение его внутренней структуры. Вот и Фаулер пишет:
Рефакторинг представляет собой процесс такого изменения программной системы, при котором не
меняется внешнее поведение кода, но улучшается его внутренняя структура.
Можно говорить о том, что понимание проблемы важнее, а главное, первичнее, специфичного решения, но неправильно говорить, что решение вообще не важно.
Здравствуйте, Nuseraro, Вы писали:
S>>Неа, тут та же путаница: рефакторинг — это общее описание проблемы ("фиговый код, нужно улучшить"). Замена стратегии на Func/Action — это конкрентый инструмент.
N>Можно говорить о том, что понимание проблемы важнее, а главное, первичнее, специфичного решения, но неправильно говорить, что решение вообще не важно.
Решение приведённое в качестве примеров — вообще не важно. Зачастую там фигня полная.
Выше -n1l- дал ссылку на шпаргалку по паттернам в творческом переложении под c#. Там как раз почти каждая реализация — пример как делать не надо.
Например, паттерн builder:
abstract class Builder
{
public virtual void BuildPartA()
{
}
public virtual void BuildPartB()
{
}
public virtual Product GetResult()
{
}
}
А теперь смотрим на реальные сценарии использования и понимаем, что реализацию ваяли от балды. Даже если отбросить лютый изврат в виде "class Director ...":
Во-первых: решаемая задача у нас — упрощение создания сложного объекта, а не возможность подмены реализации. В примере делается упор на второй пункт, первый не иллюстрируется вообще.
Во-вторых, смотрим на реальные билдеры из фреймворка.
Если билдер должен только заполнять свойства — то у билдера свойства и должны быть, а сам билдер заполняется через object initializer, см на ProcessStartInfo или на SqlConnectionStringBuilder.
Если использование билдера предполагает цепочку вызовов вида
var result = builder
.BuildPartA()
.BuildPartB()
.GetResult();
— должен быть fluent api, и, как следствие, виртуальные методы должны быть protected, а public api должно возвращать точный тип билдера.
В-третьих, не рассмотрены типовые проблемы при реализации билдера — случай, когда тип результата зависит от настройки билдера, валидацию параметров, способы избежать отслеживания состояния в билдере и т.д. и т.п.
Так что да, решение которое обычно приводится как иллюстрация, вообще не важно.
Здравствуйте, Nuseraro, Вы писали:
N>Хе-хе вижу мы разговариваем на одном языке, но называем одними словами разные вещи. Без большого желания понять друг друга пользы мы не получим
Ну, речь у нас о паттернах, поэтому я стараюсь придерживаться классики — терминологии из GoF
Тут постоянно по ветке путаются практически применимые решения, как топикстартер просил, эксклюзивно для шарпа и "решения" в стиле
решение в виде улучшения его внутренней структуры
aka
- Сова, расскажи — а как нам стать ежиками?
— Мое дело — стратегия!
Поэтому и путаница.
FDG-Рихтер и прочая суровая матчасть рассказывает в основном про решение проблем на практике. Фаулер, GoF, Кен etc — "про стратегию". Конечно, можно утверждать что разницы никакой, но тогда и смысла в обсуждении вообще никакого.
Здравствуйте, Sinix, Вы писали:
S>Неа, тут та же путаница: рефакторинг — это общее описание проблемы ("фиговый код, нужно улучшить"). Замена стратегии на Func/Action — это конкрентый инструмент.
Рефакторинг это не описание проблемы, это просто безопасные преобразования кода. Дело не в улучшении, а в изменении текущей структуры кода. А вот для чего это может понадобиться — для улучшения, для изучения, для исследования и тд — дело десятое.
Здравствуйте, -rsdn-, Вы писали:
R>нужны примеры с учетом платформы и языка программирования R>в частности интересно что такое связность от связанность (cohesion & coupling)
О паттернах
Тут уже выше давали ссылку, что я начал публикацию постов именно по теме паттернов программирования в .NET, с примерами с учетом платформы .NET и языка программирования C#.
Хотя есть масса примеров GoF паттернов привязанной к платформе и языку программирования, я бы сказал, что паттерны больше привязаны к парадигме программирования (OOP vs. FP) нежели к языку, хотя культурные особенности платформы тоже присутствуют.
Вот несколько примеров:
Шаблонный Метод
Основная суть шаблонного метода в том, что базовый класс задает каркас алгоритма, а наследник переопределяет недостающие куски, но что если вместо наследования переменные шаги задавать с помощью анонимных методов? Поскольку C# в этом плане является мультипарадигменным языком (ОО + FP фичи), то этот подход вполне оправдан. Подход на основе делегатов является очень популярным решением, хотя и применяется зачастую локально в классе (я назвал его локальным методом шаблона). С другой стороны, локальный метод шаблона часто используется для выполнения некоторых действий не зависимо от исхода "основного шага алгоритма", что в других языках (таких как С++) реализуется с помощью идиомы RAII — Resource Aquisition is Initialization. Эта же идиома используется и в языке C# в виде блока using и Disposable паттерна (который является одним из многих платформенно-зависимых паттернов проектирования).
Но в C# есть и еще одна возможность, которая может быть использована для реализации паттерна Шаблонный Метод — методы расширения. В классическом шаблонном метод каркас алгоритма задается в виде (неполиморфного) метода базового класса, а шаги задаются за счет переопределения (обычно) защищенных методов. Но что если мы зададим алгоритм шаблонного метода вне базового класса — с помощью метода расширения, а переменные шаги делегируем открытым виртуальным методам интерфейса или абстрактного класса? (привет, LINQ) В некотором роде этот подход можно рассматривать как разновидность шаблонного метода, специфичного для конкретного языка программирования. Сходство будет более очевидным, если посмотреть на другие языки, такие как Java, в которой появилась аналогичная возможность, но несколько под другим соусом в виде Default Method Implementation.
Итератор
Поскольку перебор элементов коллекций является очень распространенной операцией, то паттерн итератор обычно очень сильно интегрируется в фреймворк или базовую библиотеку, при этом вид(-ы) итераторов сильно зависит от культурных особенностей языка/платформы.
Так, например, итератор в .NET представлен интерфейсами IEnumerable/IEnumerator и IEnumerable<T>/IEnumerator<T>, который является однонаправленным итератором только для чтения. При этом в других языках/платформах итераторы другие. Так, в С++ их огромное множество: есть однонаправленные, двунаправленные, random-access, реверсные итераторы и т.п.
С другой стороны, в языке C# есть синтаксический сахар для создания итераторов/генераторов — так называемый блок итераторов (подробнее смотри в Итераторы в C#. Часть 1, Часть 2, Часть 3). При этом блок итераторов начинает смещать акцент с итераторов к генераторам, граница которых начинает стираться.
Визитор
Есть такая общая проблема в computer science под названием expression problem, основная идея которой заключается в том, что разные парадигмы программирования предоставляют "точки расширения" в одной плоскости, усложняя расширение в другой. Так, в ООП очень легко добавить новый тип в иерархию типов и переопределить пару виртуальных методов (тот самый принцип Открыт-Закрыт), но при этом сложности возникают при попытке добавить новый абстрактный метод в базовый тип иерархии. С другой стороны, ФП и структурное программирование легко позволяет добавить новую операцию над семейством типов (в ФП языках за счет pattern-matching-а), усложняя добавление нового типа в это семейство.
В результате, в ООП, появились ряд паттернов проктирования, которые упрощают добавлять операции в иерархию типов в виде паттерна посетитель (визитор).
Тут тоже могут быть платформенно и языко-зависимые реализации, в виде попытки эмуляции pattern-matching-а в языке C#, что вполне будет работать для небольшой иерархии типов, с небольшой вероятностью добавления новых типов в эту иерархию и с большой вероятностью добавления новых операций.
О cohesion&coupling
Эти два понятия являются фундаментальными понятиями в проектировании ПО, хотя они применимы и за его пределами.
Давай рассмотрим распределенную команду разработчиков. Как сделать ее максимально эффективно? Для этого нужно сосредоточить в одной локацию людей, которые будут заниматься решением одной задачи с возможно минимальным количеством взаимодействия с другими локациями (это и есть low coupling), при этом решать эта команда должна работать не над разнородными задачами, а решать одну или родственные задачи (это и есть high cohesion).
Эта проблема есть и в дизайне. Класс/модуль/приложение должны минимально зависеть от других классов/модулей/приложений, что позволит думать, развивать и улучшать класс/модуль/приложение самостоятельно не ломая и не задумываясь о соседях (это low couping). При этом класс/модуль/приложение должен решать связанный набор задач, а не быть швейцарским ножом, который умеет гайки закручивать, отчеты отправлять и в базу данных ходить (это high cohesion; нарушение Single Responsibility Principla обычно подразумевает слабый cohesion).
При этом low couling подразумевает не только то, что класс должен знать о минимальном числе других классов (это самый простой вид каплинга — физический каплинг), но и зависеть от минимального числа других классов/модулей логически. Именно логическая связанность является самой злой, когда один класс предполагает, что в корне приложения есть код, который поместил реализацию этого интерфейса в контейнер; или предполагает, что некоторый код сохранил файл в определенном месте в определенном формате; или предполагает, что есть некий другой класс, который будет публиковать события через event aggregator. Нужно понимать, что слабая связанность подразумевает возможность анализа и развития класса А в отрыве от класса Б, не зависимо от того, знает ли класс А о существовании класса Б или лишь рассчитывает на его существование.
Coupling и паттерны программирования
Есть довольно простая, но весьма хорошая книга о паттернах проектирования, под названием Head-First Design Patterns, там есть хорошая фраза:
(основная суть паттернов проектирования): выделите переменные составляющие и инкапсулируйте их, чтобы позднее их можно было изменять или расширять без воздействия на постоянные составляющие..
В целом, эта мысль пронизывает и всю книгу банды четырех: как инкапсулировать процесс создания семейства объектов (абстрактная фабрика) так, чтобы клиенты не задумывались о конкретных типах? Как инкапсулировать процесс обхода составного объекта так, чтобы клиенты не знали о его внутренней структуре (итератор)? Как бесшовно добавлять новую функциональность, чтобы клиенты класса этого не замечали (декоратор) и т.п?
Т.е. суть большинства паттернов проектирования — это борьба со сложностью и устранение лишних связей, что позволит анализировать, понимать и изменять один аспект системы, не задумываясь о множестве других, не связанных с этой главной задачей.
Здравствуйте, Sinix, Вы писали: S>Ну блин, это не паттерн в терминах оригинального GoF/Фаулера. Иначе мы так дойдём до "с++ — это сборник паттернов для ассемблера" и паттерн у нас превратится в баззворд, который обозначает так много, что не обозначает ничего.
Вы так говорите, как будто это плохо. Но С/С++ — это и есть набор паттернов для ассемблера. Точнее, С — для ассемблера, а С++ — для С.
Есть типовые проблемы, есть типовые решения. Иногда типовое решение типовой проблемы встраивают сразу в язык.
Например, в Java property — это паттерн, а в Delphi — конструкция языка. Publisher/Subscriber в Delphi — это паттерн (встроенные события там слишком убоги), а в C# — это конструкция языка. И так далее.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>Ну блин, это не паттерн в терминах оригинального GoF/Фаулера. Иначе мы так дойдём до "с++ — это сборник паттернов для ассемблера" и паттерн у нас превратится в баззворд, который обозначает так много, что не обозначает ничего. S>Вы так говорите, как будто это плохо. Но С/С++ — это и есть набор паттернов для ассемблера. Точнее, С — для ассемблера, а С++ — для С.
По большому счёту да, но тогда мы уходим в область философии, где все правы, но по-разному
Обычно всё-таки под паттернами понимают термины из gof/фаулера.
S>Есть типовые проблемы, есть типовые решения. Иногда типовое решение типовой проблемы встраивают сразу в язык. S>Например, в Java property — это паттерн, а в Delphi — конструкция языка. Publisher/Subscriber в Delphi — это паттерн (встроенные события там слишком убоги), а в C# — это конструкция языка. И так далее.
Угу. Но:
1. Если всё это обзывать паттернами, то как отличать благие пожелания по, например, обсерверу в GoF от железобетонной реализации event-ов в c#?
2. Мы начинаем путать паттерны как описание проблемы (выше кучу раз упоминался пост
от XopoSHiy) и паттерны как инструмент для решения проблем. Они не обязательно относятся как один-к-одному, достаточно вспомнить холивары на тему "вот код — это посредник, фасад, мост или адаптер?" без приведения проблемы, которую этот код пытается решить.
3. В результате путаницы появляются кошмарики типа вот этого (pdf, ссылка от -n1l-). Посмотрите примеры, там буквально каждый из разряда "обнять и плакать"
Здравствуйте, Sinix, Вы писали:
S>>Publisher/Subscriber в Delphi — это паттерн (встроенные события там слишком убоги), а в C# — это конструкция языка.
Вы так говорите, будто в C# события не убоги.
S>1. Если всё это обзывать паттернами, то как отличать благие пожелания по, например, обсерверу в GoF от железобетонной реализации event-ов в c#?
Что такое «железобетонная реализация event'ов» в C#? Вместо неё гораздо приятнее использовать Обсервер из Rx, который как раз примерно по GoF.
Здравствуйте, Qbit86, Вы писали:
Q>Вы так говорите, будто в C# события не убоги.
Если их использовать по назначению — нет, не убоги.
Q>Что такое «железобетонная реализация event'ов» в C#?
Для обсервера gof я с ходу могу предложить варианта 4 реализации, причём общего у них будет только то, что они позволяют получать оповещения.
Когда мы говорим про события шарпа, то уточнений про что мы собственно говорим обычно делать не надо
Q>Вместо неё гораздо приятнее использовать Обсервер из Rx, который как раз примерно по GoF.
У обычных событий и у IObservable сценарии использования практически не пересекаются, поэтому утверждать что A однозначно лучше B не выйдет.
Здравствуйте, Sinix, Вы писали:
Q>>Вы так говорите, будто в C# события не убоги. S>Если их использовать по назначению — нет, не убоги.
Ну и какое у них назначение?
S>У обычных событий и у IObservable сценарии использования практически не пересекаются, поэтому утверждать что A однозначно лучше B не выйдет.
Сценарии использования обычных событий строго включены в сценарии использования IObservable. Если б не легаси в повсеместном использовании встроенных событий стандартными и сторонними библиотеками, пользоваться встроенными событиями смысла вообще нет.
Здравствуйте, Qbit86, Вы писали:
S>>Если их использовать по назначению — нет, не убоги. Q>Ну и какое у них назначение?
Для событий — привязка дополнительного кода для компонент (в основном ui-компонент) для обработки единичных событий.
Для observable — управление последовательностью однотипных событий.
S>>У обычных событий и у IObservable сценарии использования практически не пересекаются, поэтому утверждать что A однозначно лучше B не выйдет. Q>Сценарии использования обычных событий строго включены в сценарии использования IObservable.
Скажем так: я имел опыт использования в продакшне и событий для того, что решалось Rx, и Rx для того, что решалось событиями. С тех пор я очень скептически отношусь к фанатизму аля "события устарели т.к. появился Rx".
Проблем (явных и неявных) всплывает куча. В основном:
1. Пользователи API начинают накручивать сложные сценарии со своими шедулерами там, где поставщик API их не ждёт. В результате на ровном месте возникают очень неприятные race conditions, которые очень любят всплывать непосредственно у клиентов.
2. Последовательности начинают использовать как события — с "тяжёлым" кодом в подписчиках, бросанием исключения в надежде на "перехватится выше по стеку", запуском асинхронных задач и "отменой" последовательностей. Работает, но поддерживаемость кода падает в разы.
3. Необходимость протаскивать disposable для отписки. Каждый решал проблему по своему, получалось не всегда.
Если бы это были единичные случаи, или повторялось только у отдельных разработчиков, или подобные косяки отлавливались бы статическим анализом, то с большей частью проблем можно было бы смириться (нравится людям — пусть пишут). По факту дешевле выходит не создавать себе проблем на ровном месте и использовать специализированный инструмент — события.
Чтобы совсем не было оффтопом. С большинством "универсальных" паттернов выходит ровно та же фигня: вместо готового инструмента изобретаем универсальный, а затем допиливаем подпорками до того, что можно решить на голом шарпе. Всей разницы: получили ещё один велосипед для изучения
Здравствуйте, Sinix, Вы писали:
S>1. Пользователи API начинают накручивать сложные сценарии со своими шедулерами там, где поставщик API их не ждёт. В результате на ровном месте возникают очень неприятные race conditions, которые очень любят всплывать непосредственно у клиентов.
Так это и с обычными событиями можно наворотить. Звучит так: «Давайте запретим вилки, так как дети могут их засунуть в розетки; взамен будем пользоваться вязальными спицами.»
S>2. Последовательности начинают использовать как события — с "тяжёлым" кодом в подписчиках
Не вижу, каким образом «.Subscribe(...)» заставляет пользователей использовать более тяжелый код, а «+= ...» — нет. В первом случае хотя бы лямбды можно использовать.
S>бросанием исключения в надежде на "перехватится выше по стеку"
То ли дело стандартные события, где исключение в одном из обработчиков внезапно влияет на остальных подписчиков.
S>3. Необходимость протаскивать disposable для отписки.
Это совсем смешно. Ты всерьёз утверждаешь, что протаскивать и источник, и подписчик событий проще, чем один только безликий IDisposable?
S>По факту дешевле выходит не создавать себе проблем на ровном месте и использовать специализированный инструмент — события.
Увы, иногда дешевле. В этом вся суть консервации принятых некогда кривых решений.
Здравствуйте, Qbit86, Вы писали:
S>>1. Пользователи API начинают накручивать сложные сценарии со своими шедулерами там, где поставщик API их не ждёт. В результате на ровном месте возникают очень неприятные race conditions, которые очень любят всплывать непосредственно у клиентов. Q>Так это и с обычными событиями можно наворотить. Звучит так: «Давайте запретим вилки, так как дети могут их засунуть в розетки; взамен будем пользоваться вязальными спицами.»
Нет. Для событий достаточно
someObj.SomeEvent += SomeHandler;
Для Rx подобного сахара нет и не предвидится по той же причине, по которой нет сахара для infoof. В результате клиенты обычно подрубают к себе в проект System.Reactive и начинают ваять свои последовательности т.к. "это ж легко". Если API выставляет события там, где они по логике больше подходят, такой фигни не возникает.
Ну, и не забываем про веселуху с обновлением rx в продукте, чтобы не поиметь приключений с несколькими версиями одной библиотеки в процессе. Сейчас не так актуально, в момент появления Rx было проблемой.
S>>2. Последовательности начинают использовать как события — с "тяжёлым" кодом в подписчиках Q>Не вижу, каким образом «.Subscribe(...)» заставляет пользователей использовать более тяжелый код, а «+= ...» — нет.
Пойнт не в этом. Обычные события такую штуку легко переживают, т.к. редко используются для обслуживания "горячего" потока данных. Observable — далеко не всегда. Пользователи начинают путаться и дуть на воду, т.е. запускать свой код через отдельный шедулер и тем самым порождают ещё больше race conditions.
Q>То ли дело стандартные события, где исключение в одном из обработчиков внезапно влияет на остальных подписчиков.
Напоминаю, речь про типовой для событий сценарий aka компонент-подписчик. "Остальных подписчиков" в 99.999% случаев просто не бывает.
S>>3. Необходимость протаскивать disposable для отписки. Q>Это совсем смешно. Ты всерьёз утверждаешь, что протаскивать и источник, и подписчик событий проще, чем один только безликий IDisposable?
Его вообще не надо протаскивать, источник как правило доступен всё время жизни подписчика.
Здравствуйте, Sinix, Вы писали:
S>По большому счёту да, но тогда мы уходим в область философии, где все правы, но по-разному
Нет, мы уходим в область научного подхода к решению проблем. S>Обычно всё-таки под паттернами понимают термины из gof/фаулера.
Это очень странный подход. Всё равно, как под термином "задача" понимать ровно задания из Демидовича, а всё остальное считать философией.
S>Угу. Но: S>1. Если всё это обзывать паттернами, то как отличать благие пожелания по, например, обсерверу в GoF от железобетонной реализации event-ов в c#?
Очень просто: также, как вы отличаете int i=0; в вашей программе от понятия "переменная".
Ещё раз подчеркну: event в C# — это уже не паттерн, это конструкция языка. Эта конструкция реализует некоторое архитектурное решение, которое в языках без нативной поддержки event-ов называется publisher/subscriber.
S>2. Мы начинаем путать паттерны как описание проблемы (выше кучу раз упоминался пост
от XopoSHiy) и паттерны как инструмент для решения проблем.
При всём уважении к XopoSHiy не стоит относиться к его посту как к священному писанию. Кроме того, вы ударяетесь в другую крайность.
XopoSHiy поясняет, что один и тот же код может быть реализацией различных паттернов, в зависимости от решаемой задачи. Но ведь и достаточно различный код может быть решением одной и той же задачи. Поэтому сводить паттерн исключительно к задаче — странно. Паттерн — это удачный приём, сочетание задачи и решения.
При этом интуитивно ожидается, что решение будет нетривиальным, поэтому конструкции языка паттернами не называют.
S>3. В результате путаницы появляются кошмарики типа вот этого (pdf, ссылка от -n1l-). Посмотрите примеры, там буквально каждый из разряда "обнять и плакать"
Ну, это уже чистый постмодернизм — искусство ради искусства.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>>Но С/С++ — это и есть набор паттернов для ассемблера S>>По большому счёту да, но тогда мы уходим в область философии, где все правы, но по-разному S>Нет, мы уходим в область научного подхода к решению проблем.
Странный спор какой-то получается.
С одной стороны, очевидно, что называть абстракции GoF, конкретные рекомендации из FDG и ещё более конкретные конструкции языка одним термином — прямой путь к замыливанию контекста.
С другой — мне уже три человека продолжают доказывать, что всё едино, хотя на практике, я уверен, сами такой терминологией никогда не пользуются
В общем я самоустраняюсь, т.к. смысла в продолжении никакого не вижу. Участникам спасибо, приятно было поспорить!
Здравствуйте, Sinix, Вы писали:
S>С другой — мне уже три человека продолжают доказывать, что всё едино, хотя на практике, я уверен, сами такой терминологией никогда не пользуются
По-моему, вы как-то превратно понимаете аргументацию. Вы можете ткнуть в то место, где я предлагаю вам называть конструкции языка паттернами?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.