Autumn SALE
Легковаговик

Легковаговик на Java

Легковаговик — це структурний патерн, який економить пам’ять завдяки розподілу спільного стану, винесеного в один об’єкт, між безліччю об’єктів.

Легковаговик дозволяє економити пам’ять, записуючи в кеш однакові дані, що використовуються різними об’єктами.

Складність:

Популярність:

Застосування: Сенс використання Легковаговика — це економія пам’яті. Тому, якщо в програмі немає такої проблеми, ви навряд чи знайдете там приклади Легковаговика.

Приклади Легковаговика в стандартних бібліотеках Java:

Ознаки застосування патерна: Легковаговик можна визначити за створюваними методами класу, які повертають закешовані об’єкти, замість створення нових.

Відтворення лісу

У цьому прикладі ми створимо і намалюємо ліс (1.000.000 дерев)! Кожному дереву відповідає свій особистий об’єкт, що має деякий стан (координати, текстуру та інше). Така програма хоч і працює, але «їсть» занадто багато пам’яті.

Багато дерев мають однакові властивості (назву, текстуру, колір). Тому ми можемо застосувати патерн Легковаговик та закешувати ці властивості в окремих об’єктах TreeType. Тепер замість зберігання цих даних у мільйонах об’єктів дерев Tree, ми будемо посилатися на один з декількох об’єктів-легковаговиків.

Клієнту навіть необов’язково знати про все це. Фабрика легковаговиків TreeType сама подбає про створення нового типу дерева, якщо буде запит щодо дерева з якимись унікальними параметрами.

trees

trees/Tree.java: Об’єкт, що містить унікальний стан дерева

package refactoring_guru.flyweight.example.trees; import java.awt.*; public class Tree { private int x; private int y; private TreeType type; public Tree(int x, int y, TreeType type) { this.x = x; this.y = y; this.type = type; } public void draw(Graphics g) { type.draw(g, x, y); } } 

trees/TreeType.java: Легковаговик, який має загальний стан кількох дерев

package refactoring_guru.flyweight.example.trees; import java.awt.*; public class TreeType { private String name; private Color color; private String otherTreeData; public TreeType(String name, Color color, String otherTreeData) { this.name = name; this.color = color; this.otherTreeData = otherTreeData; } public void draw(Graphics g, int x, int y) { g.setColor(Color.BLACK); g.fillRect(x - 1, y, 3, 5); g.setColor(color); g.fillOval(x - 5, y - 10, 10, 10); } } 

trees/TreeFactory.java: Фабрика дерев

package refactoring_guru.flyweight.example.trees; import java.awt.*; import java.util.HashMap; import java.util.Map; public class TreeFactory { static Map<String, TreeType> treeTypes = new HashMap<>(); public static TreeType getTreeType(String name, Color color, String otherTreeData) { TreeType result = treeTypes.get(name); if (result == null) { result = new TreeType(name, color, otherTreeData); treeTypes.put(name, result); } return result; } } 

forest

forest/Forest.java: GUI-ліс, який малює дерева

package refactoring_guru.flyweight.example.forest; import refactoring_guru.flyweight.example.trees.Tree; import refactoring_guru.flyweight.example.trees.TreeFactory; import refactoring_guru.flyweight.example.trees.TreeType; import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.List; public class Forest extends JFrame { private List<Tree> trees = new ArrayList<>(); public void plantTree(int x, int y, String name, Color color, String otherTreeData) { TreeType type = TreeFactory.getTreeType(name, color, otherTreeData); Tree tree = new Tree(x, y, type); trees.add(tree); } @Override public void paint(Graphics graphics) { for (Tree tree : trees) { tree.draw(graphics); } } } 

Demo.java: Клієнтський код

package refactoring_guru.flyweight.example; import refactoring_guru.flyweight.example.forest.Forest; import java.awt.*; public class Demo { static int CANVAS_SIZE = 500; static int TREES_TO_DRAW = 1000000; static int TREE_TYPES = 2; public static void main(String[] args) { Forest forest = new Forest(); for (int i = 0; i < Math.floor(TREES_TO_DRAW / TREE_TYPES); i++) { forest.plantTree(random(0, CANVAS_SIZE), random(0, CANVAS_SIZE), "Summer Oak", Color.GREEN, "Oak texture stub"); forest.plantTree(random(0, CANVAS_SIZE), random(0, CANVAS_SIZE), "Autumn Oak", Color.ORANGE, "Autumn Oak texture stub"); } forest.setSize(CANVAS_SIZE, CANVAS_SIZE); forest.setVisible(true); System.out.println(TREES_TO_DRAW + " trees drawn"); System.out.println("---------------------"); System.out.println("Memory usage:"); System.out.println("Tree size (8 bytes) * " + TREES_TO_DRAW); System.out.println("+ TreeTypes size (~30 bytes) * " + TREE_TYPES + ""); System.out.println("---------------------"); System.out.println("Total: " + ((TREES_TO_DRAW * 8 + TREE_TYPES * 30) / 1024 / 1024) + "MB (instead of " + ((TREES_TO_DRAW * 38) / 1024 / 1024) + "MB)"); } private static int random(int min, int max) { return min + (int) (Math.random() * ((max - min) + 1)); } } 

OutputDemo.png: Знімок дерев у лісі

OutputDemo.txt: Статистика споживання пам’яті

1000000 trees drawn --------------------- Memory usage: Tree size (8 bytes) * 1000000 + TreeTypes size (~30 bytes) * 2 --------------------- Total: 7MB (instead of 36MB) 

Легковаговик іншими мовами програмування

Легковаговик на C# Легковаговик на C++ Легковаговик на Go Легковаговик на PHP Легковаговик на Python Легковаговик на Ruby Легковаговик на Rust Легковаговик на Swift Легковаговик на TypeScript