Pull to refresh

Comments 86

Реквестирую такую же статью про антипаттерны.
Не уверен что тут много чего можно сказать помимо вот этой статьи. Если наберется достаточно материала и будет время — сделаю.
Там расписано про антипаттерны, но хотелось бы прочитать про антипаттерны на примерах из реального мира!
Прекрасный материал! Нет, на самом деле. Конечно нужна ещё оценка не программиста, уже давно использующего часть паттернов, а того, кто только этому учится, но всё же великолепно.
Однозначно в мемориз, спасибо.
И оценка программиста не помешает. Некоторые описания не совсем точны, state: у каждого объекта есть состояние, из-за которого объект может менять свое поведение, суть же паттерна в выделение состояния в отдельный объект; chain of responsibility: пример не отражает суть. Stragey: «вы задаете начальные условия, а как себя вести уже решает он сам (сам выбирает стратегию).» вообще то вы сами выбираете алгоритм (стратегию). Другие слишком странные: command: " включать одним выключателем как свет в комнате, так и пылесос." это вообще как возможно в реальной жизни?.. Есть же проще примеры, тот же расчет зарплаты. Decorator: «можно считать декоратором человека с кистью и красной краской. » ?! Лучше уж использовать банальный пример с пиццей и индигриентами. Proxy: это же заместитель, можно было пример с заместителями и использовать :).
упс, " Есть же проще примеры, тот же расчет зарплаты" относилось к Strategy
1. State
Во многих метафорах не говорится о том что выделять в отдельных объект, потому что это уже более предметная область. Так то ведь можно такой state даже в синглтон загнать. Главная цель была именно понять что паттерн делает, а именно меняет состояние объекта.
2. Chain of responsibility
К сожалению не смог найти метафору попроще. Возможно предложите вы — поправлю.
3. Strategy
Возьмите классический пример — валидатор. Вы используете только метод validate, а на основе параметров, вроде ('not_empty') паттерн сам производит действия, но метод который вы используете извне, везде только validate. Так что как и было сказано в описании — задаются лишь параметры, а стратегию (конкретный метод) реализует уже сам паттерн.
4. Command
Возможно некорректно выразился. У вас в пылесосе, по своей сути, точно такой же механизм как в выключателе света — соединитель/разъединитель двух проводков. Имелось ввиду именно это.
Какой именно пример вы имеете ввиду насчет зарплаты? Опять же если есть что-то попроще и понятнее — исправить статью не сложно.
5. Decorator.
А чем лучше пример с пиццей? Просто не совсем могу понять ваш ход мыслей.
6. Proxy
Чем пример с заместителем будет лучше? Полагаю если вы попробуете описать тот же принцип просто применив слово заместитель, то ничего не изменится. Могу конечно ошибаться, жду пример если это не так.
Попробовал другую метафору для Chain of responsibility, возможно так будет лучше.
Статья хорошая но слишком много текста) Разбавили бы его иллюстрации)
Да-да. Вот я «Войну и мир» в свое время поэтому же не стал читать.
Я тоже. Я лет через 15 после прохождения её в школе прочитал и понял, что и без картинок нормально :)
Любая статья должна быть интересна для прочтения а не быть просто быть просто данными
UFO just landed and posted this here
Тогда бы получилось не совсем корректно. Hierarchical visitor должен пройти по каждому элементу один раз, а у нас сейчас с лицензиями человека могут «футболить» по отдельным кабинетам несколько раз )
UFO just landed and posted this here
Книга Фримена «Паттерны проектирования» раскрывает тему паттернов на наглядных метафорах, обильно проиллюстрированных.
Советую эту книгу для плавного освоения паттернов.
Книга занимает 11 место в недавно освещенном топе habrahabr.ru/blogs/development/135897/ оригинального голосования stackoverflow.com/questions/1711/what-is-the-single-most-influential-book-every-programmer-should-read
Мне не нравится аналогия про синглтон. Синглтон — это как будто вместо того, чтобы провести в каждую квартиру по телефонному проводу (не рассказывая, куда он идет — на ближайшую телефонную станцию или на персональный спутниковый передатчик) мы говорим каждому жителю: «Что-то нам лень до тебя провод тянуть, пойди сам на ул. Ленина, дом 1, и воткни свой провод там куда-нибудь». И когда, например, станция на улице Ленина перестает справляться с количеством абонентов — у всех возникают проблемы.
Вы ушли в пример параллельного доступа к объекту (Concurrency control). Это совершенно не связано с паттерном синглтона.
Суть не в параллельном доступе, а в том что когда по каким-то причинам нужно перекинуть часть абонентов на новую станцию, то возникают проблемы — от каждого нужно новый провод тянуть.
Я имел в виду, что клиенты синглтона, помимо знания его интерфейса, знают, что это синглтон, знают, где его взять, и сами решают, когда это сделать. Иногда бывает, что эти знания — лишние для них, и могут обернуться проблемами в будущем.
за весь анализ не скажу, но вот читаю сейчас книжку «Без паники: Цифровая обработка сигналов». там очень много матанализа преподнесено наглядными средствами.
en.wikipedia.org/wiki/Service_locator_pattern

Service Locator паттерн.

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

Вот Service Locator — это такая конструкция, которая выдает по нужному вам запросу некую сущность, необходимую для решения задачи.

По сути дела, это один из способов инкапсулировать информацию о том, как создавать тот или иной объект, внутрь специального объекта. Очень клевая штука. :)
Не совсем пока понял в чем его разница с паттерном Builder?
Объясните пожалуйста, если не сложно.
В моем понимании Builder есть порождающий паттерн,
в то время как Service Locator (как я его обычно реализую) — это синглтон + реестр, который может как порождать новые объекты при обращении к нему, так и возвращать уже инстанцированные.

псевдокод
audioObject = ServiceLocator::instance()->getAudioObject() // тут может быть скрыта фабрика

videoObject = ServiceLocator::instance()->getVideoObject() // а тут может быть некий объект, однажды инстанцированный и затем возвращаемый в той самой инстанции — читай синглтон

и т.д.
и тут дело в глобальности. ServiceLocator это такая супер-пупер мегаштука, всеобъемлющая.

но кто-то может понимать иначе этот паттерн, не отрицаю :)
Builder как бы собирает объекты из кусочков, но это объекты одного класса, просто для разных экземпляров задаются разные свойства. Всегда будут пакет, изображение, сок и т. п., просто они могут быть разными, но всё равно это будет пакет с соком.

Service Locator же возвращает разные типы объектов в зависимости от кода инициализации. Пускай задача стоит доставить наш пакет сока, созданный строителем, фабрикой или ещё чем, куда захотел покупатель. Мы спрашиваем у локатора «дай нам службу доставки», и он нам соединяет на со службой доставки по номеру телефона, который директор ему дал (потому что получает откат они нам дают скидку как постоянным клиентам), а мы уже просим службу доставить сок по нужному адресу. Сегодня одна служба, а завтра может быть другая. Нам без разница, решает директор и сообщает об этом локатору служб, нам важно знать лишь что они могут доставлять то, что мы им скажем туда, куда скажем, то есть службы реализуют интерфейс «Доставить <предмет> на <адрес>».

По сути локатор служб это реестр, куда заносятся конкретные экземпляры различных служб, нужных приложению. То есть реестр со специфическим назначением. Основное назначение — реализация DI/IoC. Очень близок к паттерну IoC Container, настолько, что их часто путают, по мне так разница в том, что локатор оперирует экземплярами служб, созданных не им, а контейнер сам создаёт при необходимости. Но может ошибаюсь.
Благодарю. Расширил статью вашим комментарием и заодно добавил и dependency injection.
Неточность небольшая. Service Locator не является расширением DI, это один из методов его реализации.
Мне тоже не понравилось описание этого паттерна. По сути автор сказал — это фабрика, только где-то в недрах ее происходит собирание реальных объектов из частей.

А «в недрах» нас и не должно интересовать. интересная ссылка

Builder применяется для создания сложных объектов из отдельных частей (обычно родственных, но не обязательно). Фабрика — целого сразу. Пример Buildr-а:

interface ITreeBuilder
{
  IEntity CreateSheet();
  IEntity CreateTree(IEnumerable<IEntity> children);
  IEntity CreateRoot(IEntity part)
}

Фабрика:

itnerface ITreeFactory
{
  IEntity CreateTree();
}
На мой взгляд у вас получилась не очень хорошая статья.
Вы излишне многословны, большинство метафор витиеваты и туманы, некоторые же и вовсе не верны, при этом у вас сохраняется зависимость определения одних метафор от других.

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

Помимо упомянутой в комментариях выше книге, есть так же статья 1997 года — www.cours.polymtl.ca/inf3700/divers/nonSoftwareExample/patexamples.html, рекомендую.
Я всячески приветствую критику, однако всё же она должна быть конструктивной, чтобы не быть голословной.
Если вам есть что предложить/поправить/внести своё — предлагайте, давайте вместе делать материал более качественным и полезным для читателей. На мой взгляд это куда более грамотный подход нежели просто отписаться «у вас всё не так, как думаю я».

Как я уже говорил, это лишь небольшие метафоры, если снабдить это иллюстрациями, добавить разбавить слегка кодом и примерами — то смысл в этой статье теряется напрочь, потому что получится книга, которую указали вот в этом комментарии. Еще раз замечу — это не статья чтобы изучать паттерны, это лишь небольшое ознакомление с тем, что они иногда описывают в реальном мире.
UFO just landed and posted this here
А мой опыт говорит, что очень редко бывают методы, которые нужны всем типам объектов, ну разве что конструкторы, но они у всех разные. А если всё же нужны, то эти методы реализуются в базовом классе или определяются абстрактно/в интерфейсах, а затем реализуются в наследниках (сериализация хороший пример).

Один из столпов ООП — инкапуляция, только методы объектов должны знать об их внутренних данных, о том, что в мешке лежит. А как вы предлагаете реализовать ту же сериализацию? Функция, которая принимает произвольный объект, определяет его тип и в куче if'ов или case'ов выбирает как именно этот объект сериализовывать?
UFO just landed and posted this here
>Я считаю, что достаточно иметь один тип объектов, который имеет все методы.

God-objects? Что делать, если вызывается метод, для которого в данном «мешке» данных нет? NPE?

>— Зачем?

Возможность сменить реализацию, не меняя интерфейс. Невозможность рассогласовать состояние объекта незметно для самого объекта.

>Без всякой кучи if-ов.

Хотелось бы взглянуть. Как гуглить?

UFO just landed and posted this here
>то же, что и SQL запрос «делает», когда в базе ищут то, чего там нету.

Theris no table...? Понятно…

>Объекты как ассоциативные массивы

Больше вопросов нет…
UFO just landed and posted this here
Не все свойства объектов надо сериализовывать, циклом по всем свойствам пройтись — перебор. Уж поверьте на слово, пока вы С++ занимались, я с ассоциативными массивами работал, эмулировал с их помощью объекты из C++. Прямо как у вас «все объекты одного типа, но с разным набором данных».

Я понимаю ваш восторг от возможности динамически задавать новые свойства после C++, но вот один из самых популярных языков со слабой динамической типизацией всё больше идёт к сильной статической. Не от хорошей жизни.
UFO just landed and posted this here
«А как вы предлагаете реализовать ту же сериализацию?»
Меня этот вопрос, как старого С++ника, то же ставил в тупик. Но пришлось переучиваться… на JS, там это элементарно. Без всякой кучи if-ов.

элементарно? только не говорите о JSON.
UFO just landed and posted this here
ну, неужели Вам, цитата
как старого С++ника

кажется JSON чем-то магическим?
«любой часто используемый метод нужен всем объектам»

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

Если таковых много, значит либо вы строите сереализатор, либо недопроектировали свое решение.
UFO just landed and posted this here
>Вот мяукать мячик не может.

А что будет, если написать Мячик->Мяукни?
UFO just landed and posted this here
UFO just landed and posted this here
«Это теорема Гёделя о неполноте.»

Мы с вами не идеальных коней в вакууме строим. Наша «формальная арифметика» имеет возможность расширяться с введением новых требований, а потому можно говорить о обязательной «невыводимости», только на несуществующую функциональность. Для всего остального мы должны выдумывать новое «сложение» (или скорректировать старое), при котором функциональность будет непротиворечиво существовать.

Программа не должна 100% верно описывать реальный мир (и 1% не обязателен). Достаточно абстрактной модели, удовлетворяющей условиям, описанным в техзадании. Если в нем нет того, что кошка по вызову деструктора распадается на атомы, значит она может и не распадаться (это ее личное дело, если конечно это не вызовет утечку ресурсов).
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Интерестно, как вы будете складывать огурцы и помидоры. А самое главное, что у вас после этого получится.

Все операции в математике определены на каком-то конкретном типе объектов. Сложение натуральных чисел — для яблок, или помидоров, или сущностей. Помимо натуральных есть комплексные числа, вероятностные величины, вектора и другие математические абстракции.

Конкретная «формальная арифметика» определяет сущности и операции над ними. Не одну и не две, а столько сколько нужно. Так для векторов определено умножение на число, скалярное умножение векторов, векторное умножение векторов. Маразм ясен.
UFO just landed and posted this here
Вот только вы складываете всё-равно числа. Операция сложения в математике существует только для чисел. Вы ведь не говорите, что сложив один огурец и один огурец получилось что-то другое. Вы складываете один+один и приставляете справа «огурец»
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
И появляется куча ифов — это тут нужно сериализовывать, это тут не нужно…
UFO just landed and posted this here
Если следовать вашей логике, сохраняя поток «метафор», то в реальной жизни в принципе не нужны коробки разных размеров, можно взять одну коробку одного размера, приделать ей моторчик, колеса и ручку сверху, а потом этой коробкой заменять автомобиль, портфель, грузовик (просто побольше коробок взять) и дом. Ведь универсально же.

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

Главное не забывать при этом говорить «тр-тр-тр...»
UFO just landed and posted this here
Со своей стороны я могу только пожелать вам успехов в реализации подобного подхода.
Уверен, что если вы изобрели новый прекрасный метод разработки решающий все те проблемы для борьбы с которыми и используют ООП подход, то весь цивилизованный и разумный мир последует за вами.
UFO just landed and posted this here
Откуда функция сериализации знает какие свойства объекта надо сериализировать, а какие нет? Сериализация, например, соединения с БД для передачи по сети или сохранения на диск бессмысленна и, скорее всего, приведёт к ошибке при попытке сохранить десриализованный объект в базе. Он-то будет думать, что у него есть соединение с БД, а том, что он на другой хост попал или прошло полгода как соединение закрылось он и не догадается.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Не о вложенных полях речь идёт, а о значениях имеющих смысл только в данном контексте, после десериализации они в лучшем случае будут бесполезны, а худшем вызовут, например, access vilation и крах приложения, а то и создадут уязвимость.
UFO just landed and posted this here
А методы надо писать таким образом, что бы они работали с любым типом объектов (портфелей), SQL же работает, правда он может вернуть пустое множество, но всегда находит в портфеле не гнилые красные фасолины.
ответить

sql отвечает на вопрос ЧТО, а не на вопрос КАК
UFO just landed and posted this here
Правильно, «что делать?», а «как делать» он сам выбирает.
реляционные языки — языки программирования, оперирующие с данными как со множествами, применяя к ним основные операции теории множеств.
типичным примером является SQL. SQL основывается на теории исчисления кортежей, которое является в свою очередь направлением реляционного исчисления, а в основой оного лежит теория предикатов первого уровня.
все-таки вы не сможете с помощью них покрывать многие аспекты алгоритмического программирования.
По поводу «Стратегии» вы написали: Как устроена сама «стратегия» и какие алгоритмы внутри нее вам собственно знать и требуется.
Вы здесь частицу «не» не пропустили? «знать и не требуется».
Если ошибки нет, то поспорю с вами.
Sign up to leave a comment.

Articles