Návrhové vzory Java (design patterns): Flyweight

Dnes sa pozrieme na ďalší návrhový vzor Flyweight (java design patterns) z kategórie štrukturálnych vzorov (structural patterns). Návrhové vzory v tejto kategórii sa zaoberajú štruktúrou triedy, ako je dedičnosť (inheritance) a kompozícia (composition).

Čo je návrhový vzor Flyweight?

Flyweight je návrhový vzor, ktorý sa primárne používa na zníženie počtu vytvorených objektov, pretože sa pokúša znova použiť už existujúce objekty s rovnakými alebo podobnými vlastnosťami na úrovni triedy a nový objekt vytvorí až vtedy, keď sa nenájde žiadny zodpovedajúci objekt. Tým sa minimalizuje množstvo využívanej pamäte pre údaje zdieľanými medzi podobnými objektami.

V článku sa dozvieš:

    Aký problém návrhový vzor Flyweight rieši?

    Rieši problém v aplikáciách, ktoré pracujú s veľkým počtom objektov, ktoré by pri samostatnom uložení zaberali množstvo pamäte a nezanedbateľné sú aj náklady na ich vytváranie. Tento vzor rieši problém tak, že spoločné dáta sa extrahujú a zdieľajú medzi objektami, čím sa znižuje množstvo potrebnej pamäte a využívajú sa už vytvorené objekty.

    Príklad Flyweight implementácie v Jave

    Teraz si napíšeme program, ktorý bude simulovať jednoduchý systém na prevádzku pizzerie a na ňom si demonštrujeme práve použitie návrhového vzoru Flyweight na efektívne zdieľanie inštancií pízz a minimalizáciu počtu vytvorených objektov. Program vytvára pizzeriu, prijíma objednávky rôznych druhov pízz a obsluhuje ich. Bude pozostávať z tried Pizza, ObjednavkaPizzeriaMain.

    Pizza.java

    package designpatterns;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Pizza {
        private static Map<String, Pizza> pizzaCache = new HashMap<>();
        private String nazov;
    
        private Pizza(String nazov) {
            this.nazov = nazov;
        }
    
        public static Pizza intern(String nazov) {
            pizzaCache.putIfAbsent(nazov, new Pizza(nazov));
            return pizzaCache.get(nazov);
        }
    
        public static int pocetDruhov() {
            return pizzaCache.size();
        }
    
        @Override
        public String toString() {
            return nazov;
        }
    }

    Trieda Pizza reprezentuje druh pizzy a využíva vzor Flyweight na zdieľanie inštancií pízz s rovnakým názvom. Má metódu intern(), ktorá vytvára novú pizzu len v prípade, ak ešte neexistuje, a metódu pocetDruhov(), ktorá vracia počet rôznych druhov pízz.

    Objednavka.java

    package designpatterns;
    
    public class Objednavka {
        private Pizza pizza;
        private int cisloStolu;
    
        private Objednavka(Pizza pizza, int cisloStolu) {
            this.pizza = pizza;
            this.cisloStolu = cisloStolu;
        }
    
        public static Objednavka create(String nazov, int cisloStolu) {
            Pizza pizza = Pizza.intern(nazov);
            return new Objednavka(pizza, cisloStolu);
        }
    
        @Override
        public String toString() {
            return "Posielam pizzu " + pizza + " na stol " + cisloStolu;
        }
    }

    Trieda Objednavka reprezentuje objednávku pizzy. Každá objednávka obsahuje odkaz na konkrétnu pizzu a číslo stolu, kam má byť pizza doručená.

    Pizzeria.java

    package designpatterns;
    
    public class Pizzeria {
        private java.util.List<Objednavka> objednavky = new java.util.ArrayList<>();
    
        public void prijatObjednavku(String druh, int cisloStolu) {
            objednavky.add(Objednavka.create(druh, cisloStolu));
        }
    
        public void obsluzit() {
            for (Objednavka order : objednavky) {
                System.out.println(order);
            }
        }
    
        public int pocetPrijatychObjednavok() {
            return objednavky.size();
        }
    }

    Trieda Pizzeria predstavuje pizzeriu, ktorá prijíma objednávky a poskytuje metódy na spracovanie a výpis objednávok. Taktiež poskytuje metódu na získanie počtu prijatých objednávok.

    Main.java

    import designpatterns.Pizzeria;
    import designpatterns.Pizza;
    
    public class Main {
        public static void main(String[] args) {
            Pizzeria pizzeria = new Pizzeria();
            pizzeria.prijatObjednavku("Hawai", 2);
            pizzeria.prijatObjednavku("Quattro Formaggi", 1);
            pizzeria.prijatObjednavku("Margherita", 1);
            pizzeria.prijatObjednavku("Napoletana", 5);
            pizzeria.prijatObjednavku("Hawai", 4);
            pizzeria.prijatObjednavku("Quattro Formaggi", 3);
            pizzeria.prijatObjednavku("Margherita", 3);
            pizzeria.prijatObjednavku("Hawai", 3);
            pizzeria.prijatObjednavku("Margherita", 6);
            pizzeria.prijatObjednavku("Quattro Formaggi", 2);
            pizzeria.obsluzit();
            System.out.println();
            System.out.println("Pocet prijatych objednavok: " + pizzeria.pocetPrijatychObjednavok());
            System.out.println("Pocet pouzitych objektov typu pizza: " + Pizza.pocetDruhov());
        }
    }

    V metóde main je vytvorená inštancia pizzerie a potom sú vytvorené rôzne objednávky na pizze. Všetky objednávky sú obslúžené a nakoniec sa vypíše počet prijatých objednávok a počet použitých objektov typu Pizza. Tým sme preukázali zdieľanie objektov typu Pizza medzi rozdielnymi objednávkami.

    Výstup z tohto príkladu je:

    Screenshot výstupu z príkladu

    Zhrnutie

    Návrhový vzor Flyweight sa používa v situácii, keď potrebujeme ukladať do vyrovnávacej pamäte a opätovne využívať inštancie objektov, ktoré sú si podobné. Je zameraný najmä na optimalizovanie réžie vytvárania objektov a ich nárokov na pamäť.

    Pripravili sme pre teba súbory so spomínaným príkladom vo forme kódu, ktorý si môžeš spustiť priamo v Jave. Stiahni si kód Java Flyweight tu.

    Ak si Java programátor a hľadáš prácu, pozri si naše firemné benefity a reaguj na najnovšie pracovné ponuky.

    O autorovi

    Jozef Wagner

    Java Developer Senior

    Viac ako 10 rokov programujem v Jave, momentálne pracujem v msg life Slovakia ako Java programátor senior a pomáham zákazníkom implementovať ich požiadavky do poistného softvéru Life Factory. Vo voľnom čase si rád oddýchnem v lese, prípadne si zahrám nejakú dobrú počítačovú hru.

    Daj nám o sebe vedieť