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

Креациони обрасци

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

Креирано 2025-11-23 Sun 16:21, притисни ESC за мапу, Ctrl+Shift+F за претрагу, "?" за помоћ

Садржај

1. Фундаментални обрасци

1.1. Фундаментални обрасци

  • Обрасци који се користе за изградњу сложенијих образаца.
  • Често подржани програмским језиком.

2. Delegation

2.1. Delegation

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

2.2. Пример проблема

Delegation-concreteBad.png

2.3. Пример решења

Delegation-concreteGood.png

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

Delegation-abstract.png

2.5. Пример

interface I {
    void f();
    void g();
}
class A implements I {
    public void f() { System.out.println("A: doing f()"); }
    public void g() { System.out.println("A: doing g()"); }
}
class B implements I {
    public void f() { System.out.println("B: doing f()"); }
    public void g() { System.out.println("B: doing g()"); }
}
class C implements I {
    // delegation
    I i = new A();

    public void f() { i.f(); }
    public void g() { i.g(); }
}

// normal attributes
public void toA() { i = new A(); }
public void toB() { i = new B(); }

public class Main {
    public static void main(String[] args) {
        C c = new C();
        c.f();
        // output: A: doing f()
        c.g();
        // output: A: doing g()
        c.toB();
        c.f();
        // output: B: doing f()
        c.g();
        // output: B: doing g()
    }
}

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

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

3. Interface

3.1. Interface

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

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

Interface-Abstract.png

3.3. Пример

Interface-Concrete.png

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

  • Сервисна класа може бити замењена без утицаја на клијента.
  • Сервисна класа може имплементирати више интерфејса и наслеђивати произвољну класу.

4. Interface and Abstract Class

4.1. Interface and Abstract Class

  • Проширење Interface обрасца.
  • Желимо да клијента учинимо независним од хијерархије класа које имплементирају сервис на такав начин да можемо мењати класе које имплементирају сервис без утицаја на клијента.
  • Истовремено желимо да дефинишемо апстрактну имплементацију сервиса тако да конкретни сервиси могу да редефинишу/допуне базну имплементацију.

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

IntAndAbsCls-Abstract.png

4.3. Пример

IntAndAbsCls-Concrete.png

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

  • Конкретан сервис може бити базиран на апстрактној имплементацији али и не мора. Довољно је да имплементира интерфејс сервиса.
  • Сервисна класа може имплементирати више интерфејса и може наслеђивати произвољну класу.
  • Апстрактна класа обезбеђује базичну имплементацију чиме се развој нових сервисних класа убрзава.

5. Креациони обрасци

5.1. Креациони обрасци

  • Апстракција и локализација процеса инстанцирања објеката.
  • Чине систем независним од начина креирања и композиције објеката.

5.2. Базичне особине

Базичне особине креационих образаца су следеће:

  • Енкапсулирају знање о конкретним класама које систем користи.
  • Скривају начин на који се врши инстацирање класа и композиција објеката.

5.3. Каталог креационих образаца

Према [1] креациони обрасци су следећи:

  • Factory Method
  • Abstract Factory
  • Prototype
  • Builder
  • Singleton

6. Factory Method

6.1. Factory Method

  • Желимо да одвојимо клијента од конкретне имплементације путем Интерфејса.
  • Желимо да клијент креира објекте на такав начин да "не зна" коју конкретну класу инстанцира.

6.2. Структура

FactoryMethod.png

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

  • Инстанцирање конкретних објеката је локализовано. Програмски код није јако спрегнут са типом конкретних инстанци.
  • Класа може делегирати креирање конкретних објеката које користи на своје подкласе чиме се постиже већа флексибилност.

6.4. А шта губимо?

  • Релативно велики број класа.
  • Сваки нови Производ захтева новог Креатора.

6.5. Демонстрација обрасца Factory Method на примеру у Јави

7. Abstract Factory

7.1. Abstract Factory

  • Проширење Factory Method обрасца.
  • Креирање фамилије објеката сличних по функцији коју врше у апликацији при чему клијент (објекат који их користи) "не зна" конкренте класе објеката.

7.2. Структура

AbstractFactory.png

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

  • Инстанцирање фамилије конкретних објеката је локализовано.
  • Програмски код није јако спрегнут са типом конкретних инстанци.
  • Промена фамилије конкретних инстанци могућа је изменом програмског кода на месту где се инстанцира конкретна фабрика објеката (најчешће једна линија кода).
  • У одређеним случајевима могућа је динамичка промена фабрике објеката (нпр. Swing PLAF).

7.4. А шта губимо?

  • Релативно велики број класа.
  • Сваки нови Производ захтева нову методу у свим Креаторима и свака нова фамилија производа захтева новог конкретног Креатора и нове конкретне производе.

8. Prototype

8.1. Prototype

Креирање објекта копирањем већ постојеће инстанце.

8.2. Структура

Prototype.png

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

  • Елиминишемо потребу за постојањем креатор класа и њених наследница при коришћењу Factory Method дизајн шаблона - смањује се број потребних класа.
  • Ако је инстанцирање објеката превише "скупо" са становишта потрошње процесорског времена и меморије, клонирање већ креираних објеката може довести до убрзања и смањења потрошње меморије.
  • Уколико нам требају инстанце објеката чије стање се разликује од иницијалног али је слично већ постојећим једноставније је клонирање постојећег, сличног, објекта и измена потребних атрибута од креирања и пуне иницијализације новог објекта.

8.4. На шта треба обратити пажњу?

  • Клонирање се најчешће реализује тзв. "дубоким копирањем" (енг. deep copy).
  • Јавина clone операција је реализована као "плитко копирање" (енг. shallow copy).

8.5. Демонстрација обрасца Prototype на примеру у Јави

9. Builder

9.1. Builder

Конструкција сложених објеката поделом надлежности на онога ко "зна" како треба направити структуру сложеног објекта и онога ко "зна" како треба креирати појединачне делове.

9.2. Структура

Builder.png

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

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

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

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

9.5. Напомена

Постоји и друга врста Builder обрасца где се објекат гради у корацима употребом помоћног Builder објекта.

Пример у Јави:

public class Car {
    private String make;
    private String model;
    private int year;
    private String color;
    private int horsepower;

    private Car(Builder builder) {
        this.make = builder.make;
        this.model = builder.model;
        this.year = builder.year;
        this.color = builder.color;
        this.horsepower = builder.horsepower;
    }
    public static class Builder {
        private String make;
        private String model;
        private int year;
        private String color;
        private int horsepower;

        public Builder withMake(String make) {
            this.make = make;
            return this;
        }

        public Builder withModel(String model) {
            this.model = model;
            return this;
        }
        ...

        public Car build() {
            return new Car(this);
        }
    }
    ...
    @Override
    public String toString() {
        return "Car{" +
                "make='" + make + '\'' +
                ", model='" + model + '\'' +
                ", year=" + year +
                ", color='" + color + '\'' +
                ", horsepower=" + horsepower +
                '}';
    }

    public static void main(String[] args) {
        Car car = new Car.Builder()
                .withMake("Toyota")
                .withModel("Camry")
                .withYear(2020)
                .withColor("Blue")
                .withHorsepower(200)
                .build();

        System.out.println(car);
    }
}
Car{make='Toyota', model='Camry', year=2020, color='Blue', horsepower=200}

Може се комбиновати и са Typestate обрасцем у циљу боље контроле могућих конфигурација.

10. Singleton

10.1. Singleton

  • Потребно је да постоји само једна инстанца класе у систему. На пример: logger, регистар, јединствена конекција ка бази и сл.
  • Јединична инстанца мора бити доступна свим клијентима.

10.2. Структура

Singleton.png

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

  • Контролисани приступ јединственој инстанци.
  • Наслеђивање класе јединствене инстанце и омогућавање реконфигурације система и у време извршавања (run-time).
  • Ако је накнадно потребно, може се обезбедити постојање више од једне инстанце. На пример, Connection Pool.

10.4. Напомена

  • Singleton се данас сматра анти-обрасцем.
  • Два главна разлога:
    • Singleton је глобални објекат – глобалне варијабле лоше утичу на квалитет дизајна и на конкурентност у контексту вишенитног програмирања.
    • Singleton се тешко mock-up-ује (клијентски код је чврсто спрегнут са Singleton објектом) па је тестирање кода који га користи веома тешко. Овај проблем се може решити коришћењем Dependency Injection обрасца.

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

  • 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