Рубрика: 2. Теория программирования

Теоретические аспекты программирования

  • Про архитектуру

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

    Есть такая книга “Thinking, Fast and Slow“. На русский язык название почему-то перевели как “Думай медленно… решай быстро“, хотя буквальный перевод означает “Быстрое и медленное мышление”.

    Автор книги Даниэль Канеман – нобелевский лауреат по экономики, но книга не только про экономику. Я бы сказал, что она написана скорее в стиле занимательной психологии. Читал давно, но после прочтения, хорошо запомнилось несколько интересных идей. Самое интересное в ней про две системы мышления – быстрая и медленная.

    Быстрое мышление хорошо развивается тогда, когда есть быстрый ответ на действие (назову его знакомым для тех специалистов термином – “фидбек”). Например если взять профессию пожарного, то он “чует” опасность, его интуиции можно доверять. Если кричит бежим – надо бежать, кричит лежать – надо падать и лежать. Иначе в этой профессии не выжить, поскольку “фидбек” на действие (или бездействие) срабатывает мгновенно. Причем с возрастом интуиция у них развивается всё больше и больше. Это и есть быстрое мышление. Оно не плохое и не хорошее, оно нужно для того, чтобы экономить силы и время, а иногда даже спасает жизнь.

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

    К чему я веду.

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

    Перейдем теперь к программистам. Они могут писать грязный код, с большим количество “копипасты” (дублирования кода), сложно поддерживаемый, плохо тестируемый. Тем не менее если программа работает и как-то решает проблемы бизнеса, то о плохом качестве кода могут не знать несколько недель или даже месяцев.

    С архитектурой дела обстоят еще хуже. Для того, чтобы разбираться в этом вопросе, нужно выпустить несколько программных продуктов, посмотреть как они ведут себя на рынке, проследить как развиваются и только после этого можно получить хоть какой-то “фидбек”, чтобы в дальнейшем понять насколько были адекватны принятые архитектурные решения. При этом в большинстве случаев, программисты и DevOps-инженеры будут месяцами стоически поддерживать проект с ужасной архитектурой.

    Получается, что если слабого программиста в организации можно “разоблачить” через несколько недель или месяцев, то ошибки архитектора могут проявить себя еще позже, например, через год или два.

    Причем хороший программист не всегда будет нормальным архитектором, он может быть силен в алгоритмах и быть ценным специалистом в своей области, но быть слабым архитектором. Например выдавать настолько сложные решения, что работать с ними могут только специалисты такого же высокого уровня. Это любимая тема для противников набора в команду звездных программистов (“Rockstar Developer”-ов).

    Бывает другая ситуация, когда у программиста срабатывает своеобразный “импринтинг” и он начинает применять везде одно и тоже архитектурное решение, которому он научился в начале карьеры и полюбил. Например, я часто видел и слышал категоричные утверждения:

    • Все успешные компании используют Spring и Hibernate!
    • В проде – только Oracle (хотя сейчас чаще слышу – только PostgreSQL)!
    • Нам нужна Кафка!
    • Все используют микросервисы!
    • Только Java, т.к. C# скоро умрет (здесь вместо Java и С# – можно подставить любые другие языки программирования)!

    Это конечно звучит мощно и просто, но… нет, не надо торопиться. Здесь как раз и надо включать, то самое “медленное мышление” про которое пишет Канеман, так называемая “Вторая система”:

    • Система 1: срабатывает автоматически и очень быстро, почти не требуя усилий и не давая ощущения намеренного контроля
    • Система 2: выделяет внимание, необходимое для сознательных умственных усилий, в том числе для сложных вычислений

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

    Вот несколько рекомендаций с моей стороны.

    • Конечно замечательно, когда можно довериться интуиции. Только интуицию нужно сформировать, а для этого нужен опыт. Причем опыт не программирования, а именно проектирования архитектуры. Проверить программный код можно относительно быстро, также быстро проверить архитектуру – нет.
      Ищите человека с опытом.
    • Если опытного архитектора нет, а есть простой программист, который выполняет эту роль, то возможно его интуиция еще не развита в должной степени. Тогда ему на этапе проектирования архитектуру надо стараться думать, анализировать, искать недостающую информацию, а не действовать интуитивно. Не использовать первую систему, методика “попробуйте выключить и включить” не сработает.
    • На проекте должен быть только один архитектор, но об этом как-нибудь в другой раз…
  • Запечатывание в Java

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

    Запечатанные классы определяются с помощью ключевого слова sealed. Это нужно, чтобы ограничить в наследовании. Потенциальных наследников в таком случае нужно указать явно, через запятую после permits.

    Например так:

    public abstract sealed class Shape
        permits Circle, Rectangle, Square { ... }

    На самом деле, основной вопрос который мне задают, не как ограничить наследование, а зачем вообще запрещать или ограничивать наследование? Ведь наследование – один из столпов ООП, такое же как и инкапсуляция и полиморфизм…

    Если посмотреть официальные цели в JEP, то в них написано:

    1. Allow the author of a class or interface to control which code is responsible for implementing it.

    2. Provide a more declarative way than access modifiers to restrict the use of a superclass.

    3. Support future directions in pattern matching by providing a foundation for the exhaustive analysis of patterns.

    JEP 409: Sealed Classes

    Цели №1 и №2 под “контролировать” и “… более декларативный способ для ограничения … ” означает “мы даем вам возможность запрещать”, не раскрывая зачем это нужно. Цель №3 интереснее, в ней виден прикладной аспект, но о нем позднее.

    Начнем с того, что прикладному программисту, который пользуется готовыми библиотеками, особой пользы в sealed нет или эта польза не особо видна. Этот “инструмент для запечатывания” нужен архитектору или ведущему программисту, который пытается построить дизайн/архитектуру проекта.

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

    java.lang.Object
      ↑ org.springframework.core.io.DefaultResourceLoader
        ↑ ...context.support.AbstractApplicationContext
          ↑ ...support.AbstractRefreshableApplicationContext
            ↑ ...AbstractRefreshableConfigApplicationContext
              ↑ ...AbstractRefreshableWebApplicationContext
                 ↑ AnnotationConfigWebApplicationContext

    В случае Spring-а это сделано умышлено, это всё росло годами и хорошо показывает всю гибкость этого огромного фреймворка.

    На самом деле, большинство компаний не пишут “Spring”. Часто многим компаниям не нужен еще один фреймворк, а нужно спроектировать конкретной решение. Например, когда я разрабатываю API или архитектуру системы, часто хочется сделать такое ограничение, чтобы мой класс не наследовали “до седьмого колена”. Раньше это было сделать сложно.

    Теперь возможно.

    Если смотреть на вопрос глобально, то ограничения в программирование, это очень полезная вещь. Например некоторые радикально настроенные программисты вообще считают, что ограничение – двигатель прогресса.

    Очень ёмко эту идею изложил Роберт Мартин (также всем известный как дядюшка Боб или “Uncle Bob”) в книге Идеальная архитектура.

    Парадигмы говорят нам не столько что делать, сколько чего делать нельзя.

    Роберт Мартин.

    Здесь речь идет, не об sealed классов, а в целом о роли различных запретов и ограничениях в программировании.

    Например структурное программирование – борется с таким злом как оператор “goto”. ООП вводит ограничение на косвенную передачу управления. Функциональное программирование накладывает ограничение на присваивание.

    Конечно это слишком смелая идея, полностью принять и согласиться с ней я не могу. Например, мне кажется, что крутость ООП не только в том, что борется с передачей управлением, а ещё в том, что борется засильем глобальных переменных, а также дает возможность программистам выразить в коде “вот эти методы и поля не смей трогать!”.

    С другой стороны, в целом идея верная. Например если взять такой живой пример, как очень популярный сейчас язык программирования Python. В нем наложили запрет на плохо отформатированный код. Казалось бы люди должны страдать от того, что не могут ставить пробелы и/или таб так, как они хотят и где хотят. Тем не менее, за счет этого ограничения, Python стало особо привлекателен и выразителен.

    Вернемся к sealed классам.

    Использование запечатанных классов довольно простое.
    Перед классом или интерфейсом указываем sealed, потом указываем после permits список классов-наследников. Классы должны быть final.

    Например:

    sealed class S permits A,B,C { }

    Означает, что объект класса S может быть объектом класса A, B или C.

    S abc = new A(); // Объект abc может быть только A, B или C
    abc = new B();
    abc = new C();

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

    В качестве грубой аналогии, это можно представить как сумму множеств:

    S = тип A + тип B + тип C 
      или можно написать так:
    S = A U B U C 

    Осторожно! Это всего лишь грубая аналогия. Мои выкладки здесь никак не связанны с теорией множеств и настоящей математикой. Кто учил матан и дискретку должны это понимать.

    Теперь двигаемся дальше в сторону алгебраических типов данных. Берем произведение типов. Мы можем их сделать с помощью record.

    Например:

    record R(A a, B b) { }

    Аналогия прямого произведения множества R = A x B, которое может содержать различные комбинации объектов из A и B.
    Естественно объекты класса R также могут быть частью S.

    sealed interface S permits A,B,C,R {}
    
    record R(A a, B b) implements S {}

    Что-то вроде S = A U B U C U R , где R = A x B

    Также в permits можно использовать enum.

    sealed interface S permits A,B,C,R,E {}
    record R(A a, B b) implements S {}
    // Делаем enum для запечатанного S
    enum E implements S { AZ, BUKI, VEDI, GLAGOL, DOBRO }

    Важно понимать, что sealed это про объединение “типов”, а enum – объединение объектов одного типа. Разница как между множеством и элементами множества.

    Архитекторы языка Java нам оставили специальное ключевое слово non-sealed. Это такой аварийный люк, который можно использовать, чтобы “распечатать” запечатанный класс.

    sealed interface S permits A,B,C,R,E, Gin { }
    record R(A a, B b) implements S { }
    enum E implements S { AZ, BUKI, VEDI, GLAGOL, DOBRO; }
    // От этого класса можно наследоваться, он не final
    non-sealed class Gin { }

    Ключевое слово non-sealed очень необычное. Это первый hyphenated keyword. Другими словами написанный через дефис, т.е. в kebab-case или шашлык-нотации. Такая нотация наиболее популярна в lisp-е и в частности в clojure, но в Java встречается впервые.

    Что касается в целом последних изменений в языке и своего опыта. В последнее время активно использую record. По ощущениям, это “новшество” почти такое же крутое, как появление в 2004-ом году generic-ов в Java 5 или нормальных коллекций в 1998-ом, когда вместо Vector и Hashtable в Java 2 появились List, Map.. Постоянно думаешь, почему этого не было раньше.

    Про sealed не могу сказать также. Жду сентября 2023 года, когда выйдет Java 21 LTS. Тогда можно будет использовать новый pattern matching в полную силу.

    Про новый pattern matching в другой раз, а то итак статья очень большая получилась.

    PS: Сделал телеграм канал @prgrmdr для анонсов

  • Про JavaScript (не для JavaScript программистов).

    Последние полтора месяца пишу для одного своего заказчика графический движок на JavaScript (HTML5/Canvas), который будет рисовать в браузере некоторые их инженерные схемы. Параллельно консультирую штатных программистов, у которых не очень большой опыт работы с JavaScript-ом.

    При кажущейся простоте JavaScript не создан для легкого написания надежного кода. Для самопроверки пользуюсь jsLint-ом и периодически запускаю google closure compiler. Тем не менее, это не решает всех проблем. Даже если вы пишете правильный и аккуратный код, указываете комментарии в исходником коде для проверки типов и т.д., все равно приходится время от времени сталкиваться с работами других программистов.

    Из своих “полевых наблюдений” за программистами я понял, что у тех несчастных, которые начинают писать на JavaScript-е после других языков, возникает путанное понимание некоторых фундаментальных понятий этого языка.
    (далее…)

  • Поиск. КМП-алгоритм

    Недавно на досуге решил написать алгоритм КМП  (КнутаМорриса — Пратта) для Scala.

    Изначально, мне нужно было решить простенькую задачку – найти последовательность байт в потоке байтов. Сделал на Java. Потом, решил сделать тоже самое на Scala. Занятно, но в стандартной библиотеке коллекций Scala используется именно КМП поиск.

    Вот мой вариант.
    (далее…)

  • Самый лучший Singleton

    Из всех существующих на момент написания этого поста реализаций шаблона Singleton (одиночка) мне больше всего нравится эта:

     public class Singleton {
       // Private constructor prevents instantiation from other classes
       private Singleton() {}
    
       /**
        * SingletonHolder is loaded on the first execution of Singleton.getInstance()
        * or the first access to SingletonHolder.INSTANCE, not before.
        */
       private static class SingletonHolder {
         private static final Singleton INSTANCE = new Singleton();
       }
    
       public static Singleton getInstance() {
         return SingletonHolder.INSTANCE;
       }
     }
    

    Эту реализацию придумал  Bill Pugh. Это гениальный и очень простой способ. При помощи элегантного использования внутреннего класса Вы получаете ленивый (объект Singleton не инициализируется до моменты вызова метод getInstance())  и потоко-безопасный Singleton.

    Поскольку в классе Singleton нет статических полей которые нужно инициализировать, класс беспрепятственно загрузится. То есть Вам не нужно ждать, пока мы создадим объект Singleton в самом начале, когда загружаются классы.
    Смотрим дальше, когда объект INSTANCE будет создан? Тогда, когда мы вызовем метод getInstance(), что повлечет загрузку внутреннего класса SingletonHolder, что спровоцирует создание объекта INSTANCE. Поскольку фаза инициализации класса гарантировано (спецификацией) “не конкурента“, то у нас нет необходимости использовать synchronized и volatile. Ура!

  • Как рисовать UML диаграммы классов.

    Диаграмма классов.

    Архитекторы программного обеспечения разговаривают на языке UML. Это такая своеобразная программисткая латынь. Использовать UML напрямую для программирования  неудобно, зато многие его понимают и используют для выписывания рецептов описания архитектуры системы. Нарисовал диаграмму классов и стало понятней что к чему. Её поймет и дельфист и жаваист, и сишник и  питоньшик, и сишарпер и рубист (вобщем все кто изучал ООП).

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

    От общего к частному…

    Самое главное при создании диаграммы классов использовать принцип “от общего к частному”. На самом деле  это один из фундаментальных принципов, который великие художники прошлого открыли уже много лет назад.

    Представим, что Вы не умеете хорошо рисовать, но вам очень хочется нарисовать например чью-то голову. Вы берете карандаш, кладете лист бумаги и начинаете рисовать его левый глаз. Потратив на этот несчастный левый глаз больше часа, Вы беретесь за нос, затем за правый глаз, ухо и только потом пытаетесь дорисовать все остальное. Вполне вероятно, что итог работы Вас опечалит (не советую показывать жертве результат работы) – глаз, нос, рот и уши будут не на своем месте. Конечно, бывают среди нас гении, у которых получится шедевр, но все-таки, те, кто занимается этим профессионально проповедуют другой подход – “От общего к частному, от частного к общему”. Вначале делается эскиз, “топорный” рисунок. Затем дальнейшая проработка. Например так:

    Точно так же я советую поступать в работе с диаграммами классов в UML. Мы создаем эскиз. Выделяем основные классы, определяем отношения между ними, затем прорабатываем мультипликаторы, поля, методы и их область видимости, сигнатуру вызовов, вспомогательные классы и так далее…

    Но начинать нужно с формирования набора базовых классов. Для этого нужно просто нарисовать прямоугольники и написать в них имена основных классов. Затем постепенно прорабатывать все остальное.

    Например так:

    (далее…)

  • Хранение семантических данных. Связка: Jena / Jenabean + Sparql

    1. Jena

    В поисках средств для работы с семантическими данными (semantic web) на java можно наткнуться на  следующие решения:

    1. Jena
    2. JRDF
    3. Sesame

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

    • он позволяет работать с RDF, RDFS, OWL,
    • осуществлять запросы через  SPARQL,
    • есть возможность читать и писать из N3 и RDF-XML форматов,
    • работать с базами данными Oracle, MySQL, PostgreSQL, HSQLDB, MS SQL Server и Derby.

    Исторически, jena является разработкой выращенной в лаборатории Hewlett-Packard в рамках исследований по семантик вебу. Приблизительно с октября 2009 года HP-шники прекратили активные работы над этим проектом и стали его активно опенсорсить (под BSD-подобной лицензией).  Думаю сейчас  разработчики могут спокойно и бесплатно использовать  его без особых проблем.

    Для Jena имеется неплохой набор учебных материалов как на самом сайте, так и на других различных ресурсах (например на ibm-ком developerWorks: Introduction to Jena). Структура базовых классов простая и интуитивно понятная. Для примера, привожу краткий набор некоторых основных сущностей в библиотеке:

    • RDFNode – базовый интерфейс для ресурсов или литералов
    • Resource – RDF-ный ресурс (например <http://somewhere/JohnSmith>)
    • Literal – RDF литерал (“John Smith”)
    • Property – свойство или предикат (VCard.FN)
    • Statement – триплет “субъект” – “предикат” – “объект”
    • Model – множество триплетов

    Неплохую вводную по работе с Jena, можно прочитать на сайте  www.semantictools.ru. Также этом на сайте находится множество полезной информации для людей увлеченных семантическими технологиями.

    2. Jenabean

    Для связки между JavaBean и RDF хранилищем можно использовать библиотеку jenabean . Способ привязки базируется на аннотациях и чем-то напоминает работу с JPA — аннотациями даются указания каким образом связываются поля класса и данные в хранилище.

    Примеры, документацию и саму библиотеку можно скачать на официальной странице  проекта – http://code.google.com/p/jenabean

    Также там имеется замечательный скринкаст, в котором показано по шагам (с нуля) работа под NetBeans’e с этой библиотекой. Так что здесь какие-либо мои пояснения по установке и работе библиотеки уже не нужны, достаточно просмотреть видео на сайте.

    Далее хотелось уделить особое внимание работе  Jenabean и SPARQL.

    SPARQL – язык запроса для выгребания данных из RDF.  С его помощью можно осуществлять довольно хитрые выборки.

    Для работы через SPARQL в jenabean можно использовать класс Sparql, который может получать данные из Jena-вской модели (Model – множество триплетов) .

    Важно! В jenabean-овском  SPARQL-запросе обязательно должна быть переменная ?s, которая ссылается на требуемый вами объект. Зачем они решили сделать такую жесткую завязку  на ?s мне не понятно, может в следующих версиях придумают что-нибудь покрасивее.

    В качестве примере, можно рассмотреть кусок кода — получение списка из 10 (LIMIT 10) статей в порядке их публикации (ORDER BY ?d)  начиная с 20-ой (OFFSET 20) .

    String query = "SELECT ?s ?d WHERE " +
    "{ ?s a  . ?s  ?d } " +
    "ORDER BY ?d LIMIT 10 OFFSET 20";
    LinkedList
    list = Sparql.exec(model, Article.class, query);
  • деревья и реляционные базы данных. вложенные множества.

    Для работы с древовидными (иерархическими) структурами в первую очередь следует постараться понять какие действия будут осуществляться часто, а какие эпизодически.

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

    1.  Узел хранит информацию о родителе. Это  классика.

    CREATE TREE_NODE (ID INT ..., PARENT_ID INT, ...);
    

    Все очень просто –  узел хранит идентификатор родительского узла. Самая простая схема.

    Такую схему удобно использовать когда:

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

    Другой вариант использования, когда в основном  требуются выборки на уровне одного поколения – получить список  “детей” у данного узла или получить информацию о родителе. Например, если мы используем асинхронное получение узлов в дереве.  Тогда дерево отображается не сразу, а после нажатия пользователем на соответствующий узел, после которого идет обращение к веб-серверу на получение данных. Например, как это выглядит в  Ext GWT (GXT).

    Кстати, в некоторых базах данных существует уже готовые механизмы для работы с деревьями. В частности в ORACLE это CONNECT BY.

    2. Вложенные множества.  Узел хранит в себе информацию о своем расположение в дереве.

    CREATE TREE_NODE (ID INT ...,  LEFT INT...,  RIGHT INT...) ;

    О вложенных множествах написано сейчас в интернете уже предостаточно. Основную идею можно понять из картинки.

    и следующего SQL запроса (получение всей ветки для C.1):

    SELECT id FROM tree WHERE left <= 5  AND right => 6 ORDER BY left; -- в итоге получим узлы A, B.2, C.1

    (далее…)

  • Сортировка за O(N)-время

    Случайно наткнулся на статью на java.dzone.comFast O(n) Integer Sorting Algorithm!

    Всегда считал что O(n*log(n) ) это очень хороший показатель.  Например, стандартная реализация сортировки в Java 6 является слегка модифицированным вариантом merge sort, которая  соответственно дает время n*log(n).  Получить ультра ускорялку сортировки можно используя дополнительные хитрости: используя дополнительные знания о самих объектах которые мы сортируем + ограничения на возможные их значения.

    Если верить википедии Гарольд Сьюард (Harold H. Seward) в 1954 году из MIT изобрел ультра крутой способ сортировки  – radix sort (поразрядная сортировка), а также разработал counting sort (сортировка подсчетом).
    При такой сортировки мы не используем Comparator, т.е. сравнение и перестановка элементов как в обычной сортировки не происходит. С другой стороны, такой метод требует дополнительной памяти и
    особо эффективен в тех случаях, когда мы сортируем большое количество натуральных чисел ограниченных по возможным принимаемым значениям. Например: массив из 1000000 целых чисел, которые принимают значения от 0 до 1000.
    (далее…)

  • шаблоны проектирования

    GoF Шаблоны проектирования

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

    Приемы объектно-ориентированного проектирования. Паттерны проектирования Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес

    “Классикой жанра” считается книжка “банды четырех” (англ: “Gang Of Four” или просто GoF) – книга написанная Эрихом Гаммой и соавторами в 1995 году и посвященная шаблонам проектирования.

    Стивен Стелтинг, Олав Маассен. Применение шаблонов Java. Библиотека профессионала

    Из книг по шаблоном именно для Java-программистов читал “Применение шаблонов Java”.

    Описание шаблонов, которые я здесь привожу построено на следующем принципе.

    Название шаблона – ссылка на статью в википдеии. Пример – фрагмент java-кода, где  этот шаблон может встречаться в стандартном Java API или в каком-то “бытовом” случае.

    Для шаблонов, примеры которых я не смог найти место в стандартной реализации, приводиться просто его краткое описание. Другими словами там, где можно обойтись от использования “оригнальных” и “понятных” примеров ООП – CarFactory, Car, Ford или Fruit, Apple или Person, Student, Prepod и так далее, я старался использовать привычные для программиста StringBuilderMouseAdapter, Reader. Т.е. классы, объекты которых мы используем каждый день.

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

    Creational/Порождающий

    AbstractFactory

    // Создает DOM Document Builder в зависимости от используемого парсера
    DocumentBuilderFactory documentBuilderFactory = ...;
    documentBuilderFactory.newDocumentBuilder();
    

    (далее…)