Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Структуры данных - лекция: шаблоны проектирования

Anton
January 11, 2025

Структуры данных - лекция: шаблоны проектирования

Лекция курса "Структуры данных"
Архитектура приложения, проектирование приложения: шаблоны (паттерны) проектирования в стиле ООП
- Объектно-ориентированное программирование (ООП) Object oriented programming (OOP) vs Объектно-ориентированное проектирование (дизайн) (ООП/ООД) Object oriented design (OOD)
- Объектно-ориентированное проектирование
- Шаблоны проектирования
- Книги
- Одиночка Singleton [синглтон]
- Фабрика Factory [фактори]
- Наблюдатель Observer (Слушатель событий Event listener)
- Модель-Представление Model-View (MV)
- Модель-Представление-Контроллер Model-View-Controller (MVC)
- Работа с базами данных
- Еще шаблоны (из Э. Гаммы)

https://vk.com/video53223390_456239471

Anton

January 11, 2025
Tweet

More Decks by Anton

Other Decks in Education

Transcript

  1. • Объектно-ориентированное программирование (ООП) Object oriented programming (OOP) • Объектно-ориентированное

    проектирование (дизайн) (ООП/ООД) Object oriented design (OOD) • OOP vs OOD (на английском языке аббревиатуры отличаются, на русском — совпадают)
  2. Объектно-ориентированное проектирование • Объектная модель приложения: описываем предметную область языком

    объектов и связей между ними • Логика исполнения — задача №2 (вторая после того, как сделали модель) • Развитие ОО-интуиции практикой
  3. Шаблоны проектирования • Люди не первый год проектируют приложения в

    терминах ООП, за это время успели накопить некоторый опыт • Предметные области разные, а внутренняя кухня схожая • Не все можно (или удобно) реализовать в виде библиотеки • Типовые рекомендации к проектированию архитектуры приложения • Шаблоны (паттерны) проектирования • англ.: design patterns
  4. Примеры • Фабрика (Factory) • Одиночка (Singleton) • Слушатель событий

    (Event listener) • Модель/представление (Model/View) • Модель/представление/контроллер (Model/View/Controller - MVC)
  5. Книги • Приемы объектно-ориентированного проектирования. Паттерны проектирования, Эрих Гамма, Ричард

    Хелм, Ральф Джонсон, Джон Влиссидес, 1994 (регулярно переиздаётся и допечатывается) оригинал: Design Patterns: Elements of Reusable Object-Oriented Software • Паттерны проектирования, Эрик Фримен, Элизабет Фримен, Кэтти Сьерра, Берт Бейтс, 2004 (регулярно переиздаётся и допечатывается) оригинал: Head First Design Patterns: A Brain-Friendly Guide • Интернет, Хабр, Википедия
  6. Например: ConfigOptions • getOptX • getOptY • setOptX • setOptY

    • Чтобы загружалось из файла (settings.cfg) или СУБД • И сохранялось туда же
  7. public class ConfigOptions() { private int optX; private String optY;

    public int getOptX() { return optX; } public String getOptY() { return optY; } public void setOptX(int newVal) { this.optX = newVal; } public void setOptY(String newVal) { this.optY = newVal; } }
  8. Варианты • Создавать объект ConfigOptions везде, где обращаемся к настройкам

    - во-первых, это некрасиво - можем получить всякие неприятные конфликты при сохранении файла из разных мест • Сделать все поля и методы статическими (static) - плохой тон • Применить шаблон «Одиночка»
  9. Шаблон «Одиночка» • Ровно 1 экземпляр класса на всё приложение

    • Доступ к этому экземпляру из любой точки приложения
  10. public class ConfigOptions() { private static ConfigOptions instance; private ConfigOptions()

    {} public static ConfigOptions getInstance() { if(instance == null) { instance = new ConfigOptions(); } return instance; } [...] public int getOptX() { […] } public String getOptY() { […] } [...] }
  11. Замечание (для Java) • Существует ненулевая вероятность, что предложенный (прямолинейный)

    вариант реализации создаст два экземпляра ConfigOptions в многопоточном приложении (в instance останется последний) • Поэтому обычно используют немного другой вариант инициализации instance — в блоке инициализации static
  12. public class ConfigOptions() { private static ConfigOptions instance; private ConfigOptions()

    {} public static ConfigOptions getInstance() { if(instance == null) { instance = new ConfigOptions(); } return instance; } [...] public int getOptX() { […] } public String getOptY() { […] } [...] }
  13. public class ConfigOptions() { private static ConfigOptions instance; private ConfigOptions()

    {} static { instance = new ConfigOptions(); } public static ConfigOptions getInstance() { return instance; } [...] public int getOptX() { […] } public String getOptY() { […] } [...] }
  14. Например: темы виджетов • Виджеты (элементы управления): Button (кнопка), Label

    (текст), Switch (переключатель) • Темы (внешний вид): Native (стиль операционной системы), Fancy (симпатичный)
  15. Button btn1 = new NativeButton(); Button btn2 = new FancyButton();

    Label lbl1 = new FancyLabel(); Label lbl2 = new FancyLabel(); Switch sw1 = new NativeSwitch();
  16. Какая здесь тема оформления? Как её сменить? • Нужен способ

    создавать объекты-виджеты по месту • Мы не должны знать/выбирать тему (конкретную реализацию) в месте создания виджета
  17. Дополнительно • Возможность указать тему в настройках (одно название темы

    определяет оформление сразу всех виджетов) • Загрузка новой темы с выбором произвольной темы из настроек (хотя бы) при старте приложения
  18. class NativeWidgetFactory implements WidgetFactory { public Button createButton() { return

    new NativeButton(); } [...] } class FancyWidgetFactory implements WidgetFactory { public Button createButton() { return new FancyButton(); } [...] }
  19. WidgetFactory wfact = new NativeWidgetFactory(); //WidgetFactory wfact = new FancyWidgetFactory();

    Button btn1 = wfact.createButton(); Button btn2 = wfact.createButton(); Label lbl1 = wfact.createLabel(); Label lbl2 = wfact.createLabel(); Switch sw1 = wfact.createSwitch();
  20. WidgetFactory wfact = ConfigOptions.getInstance().getWidgetFactory(); Button btn1 = wfact.createButton(); Button btn2

    = wfact.createButton(); Label lbl1 = wfact.createLabel(); Label lbl2 = wfact.createLabel(); Switch sw1 = wfact.createSwitch();
  21. Задание • Добавьте настройки ConfigOptions в одну из лаб •

    Например: игра «кто быстрее» — до скольки считать, какая задержка между удалениями введенных чисел • Или: лаба с сетевым графиком
  22. MyButton • Надпись («сохранить в файл») • Нарисовать (draw) -

    написать текст (this.надпись) • Обработать нажатие - выполнить действие (сохранить в файл)
  23. У нас есть кнопка «сохранить в файл» • Хотим добавить

    еще одну кнопку: «отправить в интернет»
  24. Как сделать так, чтобы разные экземпляры кнопки выполняли разные действия?

    • Выполнять разные участки внутри MyButton по условию (совсем плохо) • Абстрактный onClick (получше, но не всегда удобно) • Вынести обработчик событий за пределы класса: добавить наблюдателя EventListener
  25. • btn1 = new MyButton(«Сохранить в файл»); btn1.setOnClickListener(new OnClickListener() {

    void onClick() { // сохраняем в файл } } • btn2 = new MyButton(«Отправить в интернет»); btn2.setOnClickListener(new OnClickListener() { void onClick() { // отправляем в интернет } }
  26. MyButton • Надпись («сохранить в файл») • Нарисовать (draw) -

    написать текст (this.надпись) • Обработать нажатие - выполнить действие (сохранить в файл) - clickListener.onClick(); • слушатель OnClickListener clickListener setOnClickListener(OnClickListener cl): clickListener = cl
  27. Много слушателей (как вариант) • OnClickListener listeners[]; или • javax.swing.event.EventListenerList

    listeners; • addOnClickListener(OnClickListener cl) • Обработать нажатие: пробежать по всем слушателям listeners в цикле
  28. ru.wikipedia.org/wiki/Model-View-Controller • Концепция MVC была описана Трюгве Реенскаугом в 1978

    году, работавшем в научно- исследовательском центре «Xerox PARC» над языком программирования «Smalltalk». Позже, Стив Бурбек реализовал шаблон в Smalltalk-80. • Окончательная версия концепции MVC была опубликована лишь в 1988 году в журнале Technology Object.
  29. • Хотим хранить данные, не думая о том, как их

    будем отображать • Или вообще их отображать будем не мы • Или мы хотим отображать одни и те же данные разными способами • Но тот, кто будет их отображать, должен иметь возможность получить всю необходимую информацию для отрисовки • И оперативно получать информацию в том случае, если модель без его ведома (из другого представления или по своему внутреннему усмотрению) изменится (через паттерн Наблюдатель)
  30. SwitchModel • Boolean enabled • switchOn(вкл) enabled = true fireEnabledChange();

    • switchOff(выкл) enabled = false fireEnabledChange(); • switch() (переключить) if(enabled) switchOff() else switchOn() • private SwitchModelListener listeners[] • addModelListener (lis) • fireEnabledChange for ml : listeners: ml.onEnabledChange
  31. SwitchView • sm: SwitchModel • Рисовать if sm.isEnabled() рисовать ВКЛ

    else рисовать ВЫКЛ • SwitchModelListener sml - onEnabledChage: нужно перерисовать • onMouseClick sm.switch()
  32. Кстати • Если модель вдруг регулярно меняется, но слушатель событий

    не предусмотрен, • можно организовать старый добрый poll (периодически опрашивать)
  33. MV + Controller • К обычной Model-View добавляем еще один

    слой — логика обработки действий пользователя выделяется из представления в Контроллер • Влияем на модель: Представление → Контроллер → Модель
  34. Например: «сохранить в файл» • SaveButton.onClick: model.save() • Теперь хотим

    это действие выполнять из меню, кнопкой на панели инструментов, сочетанием Ctrl+S и по таймеру • Чтобы не копировать код, можно вынести его в отдельное место: • Controller:saveModel(): model.save() • Дальше во всех перечисленных местах: controller.saveModel() • Логика в контроллере, конечно, может быть посложнее • Не обязательно выносить в отдельный класс
  35. Java+Swing • javax.swing.JTable + TableModel (DefaultTableModel) • javax.swing.JTree + TreeModel

    (DefaultTreeModel) • javax.swing.JList + ListModel (DefaultListModel) • и т.п.
  36. Андроид • Представление (вид) - файл xml (разметка, кода нет)

    • Файл с кодом (контроллер) - Activity, Fragment или Component - загружает вид из XML - подключает обработчиков событий - взаимодействует с моделью • Модель: ваш код, инфраструктура приложения, источники данных для списков, слой взаимодействия с СУБД (DAO/ORM и т.п) и т.п.
  37. Веб • Динамические странички HTML (php, jsp, ...) - Плохо:

    генерация кода HTML вперемешку с логикой запроса к СУБД (всё кусками в одном файле) - Получше: использовать генераторы шаблонов страниц (вынести представление в отдельный файл) • ReactJS: MVC на уровне архитектуры (отображение в браузере на клиенте, логика и данные — на сервере)
  38. Работа с базами данных • DAO — Data access object

    (паттерн) • ORM (класс фреймворков, реализующих паттерн как библиотека)
  39. Задание: Сетевой график - MVC • GraphModel - вершины -

    ребра - связать() - разорватьСвязь() … - события • GraphView (представление в виде вершин и ребер) • TableView (представление в виде таблицы)
  40. • Abstract Factory (абстрактная фабрика) (93) Предоставляет интерфейс для создания

    семейств, связанных между собой, или независимых объектов, конкретные классы которых неизвестны. • Adapter (адаптер) (141) Преобразует интерфейс класса в некоторый другой интерфейс, ожидаемый клиентами. Обеспечивает совместную работу классов, которая была бы невозможна без данного паттерна изза несовместимости интерфейсов. • Bridge (мост) (152) Отделяет абстракцию от реализации, благодаря чему появляется возможность независимо изменять то и другое. • Builder (строитель) (103) Отделяет конструирование сложного объекта от его представления, позволяя использовать один и тот же процесс конструирования для созданияразличных представлений.
  41. • Chain of Responsibility (цепочка обязанностей) (217) Можно избежать жесткой

    зависимости отправителя запроса от его получателя, при этом запросом начинает обрабатываться один из нескольких объектов. Объектыполучатели связываются в цепочку, и запрос передается по цепочке, пока какойто объект его не обработает. • Command (команда) (226) Инкапсулирует запрос в виде объекта, позволяя тем самым параметризовывать клиентов типом запроса, устанавливать очередность запросов, протоколировать их и поддерживать отмену выполнения операций. • Composite (компоновщик) (162) Группирует объекты в древовидные структуры для представления иерархий типа «частьцелое». Позволяет клиентам работать с единичными объектами так же, как с группами объектов. • Decorator (декоратор) (173) Динамически возлагает на объект новые функции. Декораторы применяются для расширения имеющейся функциональности и являются гибкой альтернативой порождению подклассов.
  42. • Facade (фасад) (183) Предоставляет унифицированный интерфейс к множеству интерфейсов

    в некоторой подсистеме. Определяет интерфейс более высокого уровня, облегчающий работу с подсистемой. • Factory Method (фабричный метод) (111) Определяет интерфейс для создания объектов, при этом выбранный класс инстанцируется подклассами. • Flyweight (приспособленец) (191) Использует разделение для эффективной поддержки большого числа мелких объектов. • Interpreter (интерпретатор) (236) Для заданного языка определяет представление его грамматики, а также интерпретатор предложений языка, использующий это представление. • Iterator (итератор) (173) Дает возможность последовательно обойти все элементы составного объекта, не раскрывая его внутреннего представления.
  43. • Mediator (посредник) (263) Определяет объект, в котором инкапсулировано знание

    о том, как взаимодействуют объекты из некоторого множества. Способствует уменьшению числа связей между объектами, позволяя им работать без явных ссылок друг на друга. Это, в свою очередь, дает возможность независимо изменять схему взаимодействия. • Memento (хранитель) (272) Позволяет, не нарушая инкапсуляции, получить и сохранить во внешней памяти внутреннее состояние объекта, чтобы позже объект можно было восстановить точно в таком же состоянии. • Observer (наблюдатель) (281) Определяет между объектами зависимость типа одинкомногим, так что при изменении состоянии одного объекта все зависящие от него получают извещение и автоматически обновляются. • Prototype (прототип) (121) Описывает виды создаваемых объектов с помощью прототипа и создает новые объекты путем его копирования.
  44. • Proxy (заместитель) (203) Подменяет другой объект для контроля доступа

    к нему. • Singleton (одиночка) (130) Гарантирует, что некоторый класс может иметь только один экземпляр, и предоставляет глобальную точку доступа к нему. • State (состояние) (291) Позволяет объекту варьировать свое поведение при изменении внутреннего состояния. При этом создается впечатление, что поменялся класс объекта. • Strategy (стратегия) (300) Определяет семейство алгоритмов, инкапсулируя их все и позволяя подставлять один вместо другого. Можно менять алгоритм независимо от клиента, который им пользуется.
  45. • Template Method (шаблонный метод) (309) Определяет скелет алгоритма, перекладывая

    ответственность за некоторые его шаги на подклассы. Позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры. • Visitor (посетитель) (314) Представляет операцию, которую надо выполнить над элементами объекта. Позволяет определить новую операцию, не меняя классы элементов, к которым он применяется.