Легковаговик (шаблон проектування)

Призначення

Використовується для ефективної підтримки (в першу чергу для зменшення затрат пам'яті) великої кількості дрібних об'єктів.

Опис

Шаблон Легковаговик (Flyweight) використовує загальнодоступний легкий об'єкт (flyweight, легковаговик), який одночасно може використовуватися у великій кількості контекстів. Стан цього об'єкта поділяється на внутрішній, що містить інформацію, незалежну від контексту, і зовнішній, який залежить або змінюється разом з контекстом легковаговика. Об'єкти клієнтів відповідають за передачу зовнішнього стану легковаговика, коли йому це необхідно.

Переваги

  • Зменшує кількість об'єктів, що підлягають обробці.
  • Зменшує вимоги до пам'яті.

Застосування

Шаблон Легковаговик можна використовувати коли:

  • В програмі використовується велика кількість об'єктів.
  • Затрати на збереження високі через велику кількість об'єктів.
  • Більшість станів об'єктів можна зробити зовнішніми.
  • Велика кількість груп об'єктів може бути замінена відносно малою кількістю загальнодоступних об'єктів, однократно видаливши зовнішній стан.
  • Програма не залежить від ідентичності об'єктів. Оскільки об'єкти-легковаговики можуть використовуватися колективно, то тести на ідентичність будуть повертати значення "істина" ("true") для концептуально різних об'єктів.

 

Діаграма UML

 

 

4.7. Фасад (Facade) /Матеріал відсутній/

5. Шаблони поведінки

Шаблони поведінки (англ. behavioral patterns) — шаблони проектування, що пов'язані з алгоритмами та розподілом обов'язків поміж об'єктів. Мова в них йде не тільки про самі об'єкти та класи, але й про типові способи їхньої взаємодії. Шаблони поведінки характеризують складний потік керування, котрий досить важко прослідкувати під час виконання програми. Увага акцентована не на потоці керування, а на зв'язках між об'єктами.

У шаблонах поведінки рівня класу використовується спадкування — щоб розподілити поведінку поміж різних класів.

У шаблонах поведінки рівня об'єкта використовується композиція. Деякі з них описують, як за допомогою кооперації багато рівноправних об'єктів пораються із завданням, котре жодному з них не під силу. Тут є важливим те, як об'єкти отримують інформацію про існування один одного. Об'єкти-колеги можуть зберігати посилання один на одного, але це посилює ступінь зв'язаності системи. За максимального рівня зв'язаності кожному об'єкту довелось би мати інформацію про всі інші. Деякі з наведених шаблонів вирішують цю проблему.

 

5.1. Відвідувач. Матеріал відсутній.

Інтерпретатор (шаблон проектування)

Інтерпретатор (англ. Interpreter) — шаблон проектування, відноситься до класу шаблонів поведінки.

Призначення

Для заданої мови визначає представлення її граматики, а також інтерпретатор речень цієї мови.

Мотивація

У разі, якщо якась задача виникає досить часто, є сенс подати її конкретні проявлення у вигляді речень простою мовою. Потім можна буде створити інтерпретатор, котрий вирішує задачу, аналізуючи речення цієї мови.

Наприклад, пошук рядків за зразком — досить розповсюджена задача. Регулярні вирази — це стандартна мова для задання зразків пошуку.

Застосовність

Шаблон Інтерпретатор слід використовувати, коли є мова для інтерпретації, речення котрої можна подати у вигляді абстрактних синтаксичних дерев. Найкраще шаблон працює коли:

  • граматика проста. Для складних граматик ієрархія класів стає занадто громіздкою та некерованою. У таких випадках краще застосовувати генератори синтаксичних аналізаторів, оскільки вони можуть інтерпретувати вирази, не будуючи абстрактних синтаксичних дерев, що заощаджує пам'ять, а можливо і час;
  • ефективність не є головним критерієм. Найбільш ефективні інтерпретатори зазвичай не працюють безпосередньо із деревами, а спочатку транслюють їх в іншу форму. Так, регулярний вираз часто перетворюють на скінченний автомат. Але навіть у цьому разі сам транслятор можна реалізувати за допомогою шаблону інтерпретатор.

Структура

UML діаграма, що описує структуру шаблону проектування Інтепретатор

  • AbstractExpression — абстрактний вираз:
    • оголошує абстрактну операцію Interpret, загальну для усіх вузлів у абстрактному синтаксичному дереві;
  • TerminalExpression — термінальний вираз:
    • реалізує операцію Interpret для термінальних символів граматики;
    • необхідний окремий екземпляр для кожного термінального символу у реченні;
  • NonterminalExpression — нетермінальний вираз:
    • по одному такому класу потребується для кожного граматичного правила;
    • зберігає змінні екземпляру типу AbstractExpression для кожного символу;
    • реалізує операцію Interpret для нетермінальних символів граматики. Ця операція рекурсивно викликає себе для змінних, зберігаючих символи;
  • Context — контекст:
    • містить інформацію, глобальну по відношенню до інтерпретатору;
  • Client — клієнт:
    • будує (або отримує у готовому вигляді) абстрактне синтаксичне дерево, репрезентуюче окреме речення мовою з даною граматикою. Дерево складено з екземплярів класів NonterminalExpression та TerminalExpression;
    • викликає операцію Interpret.

Відносини

  • клієнт будує (або отримує у готовому вигляді) речення у вигляді абстрактного синтаксичного дерева, у вузлах котрого знаходяться об'єкти класів NonterminalExpression та TerminalExpression. Далі клієнт ініціалізує контекст та викликає операцію Interpret;
  • у кожному вузлі виду NonterminalExpression через операції Interpret визначається операція Interpret для кожного підвиразу. Для класу TerminalExpression операція Interpret визначає базу рекурсії;
  • операції Interpret у кожному вузлі використовують контекст для зберігання та доступу до стану інтерпретатору.

Ітератор

Ітератор (англ. Iterator) — шаблон проектування, відноситься до класу шаблонів поведінки.

Призначення

Надає спосіб послідовного доступу до всіх елементів складеного об'єкта, не розкриваючи його внутрішнього улаштування.

Мотивація

Складений об'єкт, скажімо список, повинен надавати спосіб доступу до своїх елементів, не розкриваючи їхню внутрішню структуру. Більш того, іноді треба обходити список по-різному, у залежності від задачі, що вирішується. При цьому немає ніякого бажання засмічувати інтерфейс класу Список усілякими операціями для усіх потрібних варіантів обходу, навіть якщо їх усі можна передбачити заздалегідь. Крім того, іноді треба, щоб в один момент часу існувало декілька активних операцій обходу списку.

Все це призводить до необхідності реалізації шаблону Ітератор. Його основна ідея у тому, щоб за доступ до елементів та обхід списку відповідав не сам список, а окремий об'єкт-ітератор. У класі Ітератор означений інтерфейс для доступу до елементів списку. Об'єкт цього класу прослідковує поточний елемент, тобто він володіє інформацією, які з елементів вже відвідувались.

Застосовність

Можна використовувати шаблон Ітератор у випадках:

  • для доступу до змісту агрегованих об'єктів, не розкриваючи їхнє внутрішнє улаштування;
  • для підтримки декількох активних обходів одного й того ж агрегованого об'єкта;
  • для подання уніфікованого інтерфейсу з метою обходу різноманітних агрегованих структур (тобто для підтримки поліморфної ітерації).

Структура

UML діаграма, що описує структуру шаблону проектування Ітератор

  • Iterator
    • визначає інтерфейс для доступу та обходу елементів
  • ConcreteIterator
    • реалізує інтерфейс класу Iterator;
    • слідкує за поточною позицією під час обходу агрегату;
  • Aggregate
    • визначає інтерфейс для створення об'єкта-ітератора;
  • ConcreteAggregate
    • реалізує інтерфейс створення ітератора та повертає екземпляр відповідного класу ConcreteIterator

Відносини

ConcreteIterator відслідковує поточний об'єкт у агрегаті та може вирахувати наступний.

Використання

C#

В мові програмування C# шаблон ітератор є вбудованим, його використання можливе за допомогою оператору foreach, за умови, що відповідний контейнер реалізує інтерфейс IEnumerable.

Наприклад:

string[] strings = new string[] { "one", "two", "three" };foreach (string str in strings){ Console.WriteLine(str);}

Таку форму запису можна замінити на більш низько-рівневу, але еквівалентну:

string[] strings = new string[] { "one", "two", "three" };IEnumerator enumerator = strings.GetEnumerator();while (enumerator.MoveNext()){ Console.WriteLine((string)enumerator.Current);}