Софтверски обрасци и компоненте

Обрасци понашања

Проф. др Игор Дејановић (igord на uns ac rs)

Креирано 2025-12-02 Tue 20:46, притисни ESC за мапу, Ctrl+Shift+F за претрагу, "?" за помоћ

Садржај

1. Обрасци понашања

  • Баве се алгоритмима и расподелом одговорности између објеката.
  • Не дефинишу само образац структуре већ и образац комуникације између објеката.

2. Iterator

2.1. Iterator

Омогућава приступ елементима колекције секвенцијално без откривања конкретне репрезентације колекције.

2.2. Структура обрасца

Iterator-Abstract.png

2.3. Јава имплементација

Итератор образац је директно подржан у јавиним стандардним библиотекама – интерфејси Iterable<E> и Iterator<E>.

2.4. Јава имплементација

Iterator-Java.png

2.5. Јава имплементација - While петља

List<Integer> intList = new ArrayList<Integer>();
Iterator<Integer> i = intList.iterator();
while(i.hasNext()){
    Integer a = i.next();
    System.out.println(a);
}

2.6. Јава имплементација - ForEach петља

Итератори су подржани директно у Јава програмском језику. For-each петља у јави се може користити за било који објекат који имплементира Iterable<E> интерфејс или за јава низове.

List<Integer> intList = new ArrayList<Integer>();
for(Integer i: intList){
    System.out.println(i);
}

3. Command

3.1. Command

  • Енкапсулација захтева за обрадом у виду објекта.
  • Омогућава креирање редова за обраду (Queues) као и undo операције.
  • Познат и под називима Action и Transaction.

3.2. Структура обрасца

Command-Abstract.png

3.3. Сарадња учесника

Command-Sequence.png

3.4. Шта добијамо?

  • Раздвајамо објекат који иницира извршавање операција од онога који "зна" како операцију треба извршити.
  • Command објекти су објекти првог реда. Могу се третирати као и сви други објекти.
  • Команде се могу компоновати (употребом Composite обрасца) и формирати сложеније команде – макро команде.
  • Нове команде се лако додају – није потребно изменити постојеће класе.

4. Mediator

4.1. Mediator

  • Објекат који енкапсулира знање о интеракцији групе објеката.
  • Омогућава слабо спрезање (loose coupling) објеката тако што објекти не референцирају једни друге директно.

4.2. Структура обрасца

Mediator-Abstract.png

4.3. Пример

Mediator-Concrete.png

4.4. Сарадња учесника

Mediator-Sequence.png

4.5. Шта добијамо?

  • Сложена интеракција објеката је централизована – измена се врши наслеђивањем једне класе.
  • Објекти који ступају у интеракцију су слабо спрегнути – објекте и медијатор можемо мењати независно.
  • Једноставнији протокол – везе више-на-више замењене везама један-на-више које су лакше за разумевање и измену.
  • Логика интеракције објеката је одвојена од њиховог индивидуалног понашања – инеракција се лакше анализира.
  • Проблем који може настати – монолитан и превише комплексан медијатор објекат.

5. Memento

5.1. Memento

  • Без нарушавања енкапсулације бележи и екстернализује интерно стање објекта тако да се објекат може касније вратити у идентично стање.
  • Познат и под називом Token.

5.2. Структура обрасца

Memento-Abstract.png

5.3. Сарадња учесника

Memento-Sequence.png

5.4. Шта добијамо?

  • Очувавамо енкапсулацију – мементо не открива детаље интерне имплементације Originator објекта иако се његово стање чува ван њега. Приступ Memento објекту је могућ само од стране Originator објекта.
  • Поједностављен дизајн Originator објекта – клијенти чувају стање објекта кроз Memento објекат.
  • Боља скалабилност - чување стања се препушта клијентима.
  • Коришћење Memento објеката може бити проблематично уколико је стање Originator-а дефинисано великом количином података.
  • У неким програмским језицима је тешко спречити приступ интерној структури Memento објекта од стране других објеката у систему.

6. Observer

6.1. Observer

  • Дефинише међузависност објеката тако да када се стање једног објекта промени сви зависни објекти се аутоматски обавештавају.
  • Познат и под називом Publish-Subscribe.

6.2. Структура обрасца

Observer-Abstract.png

6.3. Сарадња учесника

Observer-Sequence.png

6.4. Подршка у Јави

  • Интерфејс Observer и класа Observable у пакету java.util.
  • Механизам Listener-а у Swing-у прати овај образац.

6.5. Шта добијамо?

  • Апстрактно спрезање Observer и Observable објеката. Observable не зна конкретне класе Observer објеката већ комуницира са њима путем једноставног интерфејса.
  • Broadcast стил комуникације. Observable јавља да се промена догодила. Не мора се наводити прималац поруке. Сви заинтересовани ослушкивачи ће добити нотификацију о промени.
  • Уколико Observable не наводи у позиву поруке шта је промењено, Observer-и морају то сами да испитају што може бити "скупо".

6.6. Напомене

  • Уколико Observer посматра више Observable објеката потребно је идентификовати објекат који шаље поруку о промени – слање референце на објекат као аргумент.
  • Измена стања Observable објекта приликом обраде нотификације може довести до бесконачне рекурзије.

7. State

7.1. State

Измена понашања објекта приликом промене његовог интерног стања. Објекат се понаша као да је променио класу.

7.2. Структура обрасца

State-Abstract.png

7.3. Сарадња учесника

  • Context делегира операције зависне од стања објекту стате (ConcreteStateX).
  • Context може проследити себе у захтеву уколико стање треба да му приступа.
  • Клијенти користе искључиво Context, мада могу, уколико је потребно, поставити текуће стање.
  • Одлуку о преласку у ново стање може донети Context или текући стате објекат.

7.4. Пример

State-Concrete.png

7.5. Шта добијамо?

  • Локализација кода специфичног за одређено стање у једну класу - избегавање великих switch/if-else исказа.
  • Експлицитан прелазак између стања.

7.6. Напомене

  • Промена стања: Context или ConcreteStateX?
    • Уколико мења ConcreteStateX потребно је да приступа Context-у преко интерфејса за промену стања.
    • Негативно: стања морају да знају једна за друге.
    • Уколико Context мења стање – код може бити доста комплексан код већег броја стања.
  • Креирање и уништавање State објеката: једном при иницијализацији или при свакој промени стања.
  • Одређени програмски језици подржавају облик динамичког наслеђивања – природна подршка за State образац.

8. Strategy

8.1. Strategy

Дефинисање фамилије алгоритама и омогућавање њихове измене без утицаја на клијента.

8.2. Структура обрасца

Strategy-Abstract.png

8.3. Пример

Strategy-Concrete.png

8.4. Шта добијамо?

  • Дефинисање фамилије алгоритама. Наслеђивање стратегија се може користити за имплементацију заједничке функционалности алгоритама.
  • Измена понашања објекта динамички. Наслеђивањем контекст класе може се постићи измена функционалности али је она статичке природе.
  • Елиминација исказа услова (if-else, switch).
  • Омогућавамо клијенту избор алгоритма и његових перформанси (нпр. мањи утрошак меморије или брже извршавање).

9. Template Method

9.1. Template Method

  • Дефинисање структуре алгоритма при чему се дефинисање одређених корака оставља класама наследницама.
  • Структура алгоритма је непромењива али се одређени кораци могу променити.

9.2. Структура обрасца

TemplateMethod-Abstract.png

9.3. Пример

TemplateMethod-Concrete.png

9.4. Шта добијамо?

  • Могућност дефинисања инваријантних делова алгоритма у апстрактној класи а варијабилних делова у подкласама – спречава се дуплирање кода.
  • Инвертовање контроле – Hollywood principle

    Don’t call us, we’ll call you

  • Дефинисање тзв. hook операција. Најчешће су празне али могу имати дефинисано и стандардно понашање. За разлику од апстрактних операција, hook операције су опционе (не морају се редефинисати).

10. Visitor

10.1. Visitor

  • Раздвајање алгоритма од структуре података над којим оперише.
  • Локализација имплементације операције која се извршава над елементима сложене структуре података (нпр. чворовима стабла).

10.2. Структура

Visitor-Abstract.png

10.3. Сарадња учесника

Visitor-Sequence.png

10.4. Пример

Visitor-Concrete.png

10.5. Када користити?

  • Објектна структура садржи елементе различитих класа а потребно је извршити операцију која зависи од конкретне класе објекта.
  • Више различитих, несродних операција је потребно извршити над елементима сложене структуре а желимо избећи "загађивање", свих класа чији објекти чине сложену структуру, са новом методом за сваку операцију.
  • Хијерархија класа објектне структуре се ретко мења док додавање нових операција над структуром може бити честа операција.

10.6. Напомене

  • Visitor представља имплементацију Double Dispatch механизма. Позвана операција зависи истовремено од типа конкретног Visitor објекта као и од типа конкретног елемента структуре над којом се операција врши.
  • Сродне операције су локализоване у једној класи.

11. Chain of Responsibility

11.1. Chain of Responsibility

Избегавање јаког спрезања објекта који шаље захтев од објекта који врши обраду захтева тако што се објекти који врше обраду увезују у листу и даје се шанса сваком у низу да обради догађај све док неко не одговори позитивно на захтев (изврши обраду).

11.2. Структура

ChainOfResponsibility-Abstract.png

11.3. Пример

ChainOfResponsibility-Concrete.png

11.4. Када користити?

  • Више од једног објекта може да обради захтев а обрађивач није познат унапред.
  • Желимо да упутимо захтев једном из групе објеката а да не наводимо конкретног обрађивача експлицитно.
  • Листа могућих обрађивача може динамички да се мења у време извршавања.

11.5. Напомене

  • Две врсте: прослеђивање захтева низ ланац и после обраде или прекид прослеђивања.
  • Објекат који врши обраду није експлицитно дефинисан па не постоји гаранција да ће захтев бити обрађен.

12. Литература

  • E. Gamma, R. Helm, R. Johnson, and J. M. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley Professional, 1994
  • M. Grand, Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, John Wiley & Sons, Inc., vol. 1, 2002