浏览代码

add flyweight pattern

MrOzOn 4 年之前
父节点
当前提交
028c3f4798

+ 27 - 0
src/structural_patterns/README.MD

@@ -133,3 +133,30 @@ _-_
 - позволяет ослабить связанность между подсистемой и ее клиентами. Зачастую компоненты подсистемы сильно связаны. Слабая связанность позволяет видоизменять компоненты, не затрагивая при этом клиентов
 - фасад не препятствует приложениям напрямую обращаться к классам подсистемы, если это необходимо. Таким образом, у вас есть выбор между простотой и общностью.
 
+# [Приспособленец (Flyweight)](./flyweight/main.kt)
+
+Это структурный паттерн проектирования, который позволяет вместить бóльшее количество объектов в отведённую оперативную память.
+Применяет совместное использование для эффективной поддержки множества мелких объектов.
+
+## Другое название
+Легковес (Flyweight)
+
+## Применимость
+
+Применяйте этот паттерн, когда выполнены все нижеперечисленные условия:
+
+- в приложении используется большое число объектов
+- из-за этого затраты на хранение высоки
+- большую часть состояния объектов можно вынести вовне
+- многие группы объектов можно заменить относительно небольшим количеством совместно используемых объектов, поскольку внешнее состояние вынесено
+- приложение не зависит от идентичности объекта. Поскольку объекты-приспособленцы могут использоваться совместно, то проверка на идентичность возвратит признак истинности для концептуально различных объектов
+
+## Отношения
+
+- состояние, необходимое приспособленцу для нормальной работы, классифицируется на внутреннее или внешнее. Внутреннее состояние хранится в самом объекте ConcreteFlyweight. Внешнее состояние хранится или вычисляется клиентами. Клиент передает его приспособленцу при вызове операций
+- клиенты не должны создавать экземпляры класса TreeType напрямую, а могут получать их только от объекта TreeFactory. Это позволит гарантировать корректное совместное использование.
+
+## Результаты
+
+При использовании приспособленцев возможны затраты на передачу, поиск или вычисление внутреннего состояния на стадии выполнения, особенно если раньше оно хранилось как внутреннее. Однако такие затраты с лихвой компенсируются экономией памяти за счет совместного использования объектов-приспособленцев.
+

+ 23 - 0
src/structural_patterns/flyweight/Forest.kt

@@ -0,0 +1,23 @@
+package structural_patterns.flyweight
+
+import java.awt.Color
+import java.awt.Graphics
+import javax.swing.JFrame
+
+class Forest: JFrame() {
+    private val trees: MutableList<Tree> = mutableListOf()
+
+    fun plantTree(x: Int, y: Int, name: String, color: Color, otherTreeData: String) {
+        val treeType = TreeFactory.getTreeType(name, color, otherTreeData)
+        val tree = Tree(x, y, treeType)
+        trees.add(tree)
+    }
+
+    override fun paint(g: Graphics?) {
+        g?.let {
+            trees.forEach { tree ->
+                tree.draw(g)
+            }
+        }
+    }
+}

+ 34 - 0
src/structural_patterns/flyweight/Tree.kt

@@ -0,0 +1,34 @@
+package structural_patterns.flyweight
+
+import java.awt.Color
+import java.awt.Graphics
+
+class TreeType(private val name: String, private val color: Color, otherTreeData: String) {
+    fun draw(g: Graphics, x: Int, y: Int) {
+        g.color = Color.BLACK
+        g.fillRect(x - 1, y, 3, 5)
+        g.color = color
+        g.fillOval(x - 5, y - 10, 10, 10)
+    }
+}
+
+class Tree(private val x: Int, private val y:Int, private val treeType: TreeType){
+    fun draw(g: Graphics){
+        treeType.draw(g, x, y)
+    }
+}
+
+class TreeFactory {
+    companion object {
+        private val treeTypes: MutableMap<String, TreeType> = mutableMapOf()
+
+        fun getTreeType(name: String, color: Color, otherTreeData: String): TreeType {
+            var result = treeTypes[name]
+            if (result==null) {
+                result = TreeType(name, color, otherTreeData)
+                treeTypes.put(name, result)
+            }
+            return result
+        }
+    }
+}

+ 28 - 0
src/structural_patterns/flyweight/main.kt

@@ -0,0 +1,28 @@
+package structural_patterns.flyweight
+
+import java.awt.Color
+import kotlin.random.Random
+
+fun main(){
+    val CANVAS_SIZE = 500
+    val TREES_TO_DRAW = 1000000
+    val TREE_TYPES = 2
+
+    val forest = Forest()
+    (0..TREES_TO_DRAW / TREE_TYPES).forEach { index ->
+        forest.plantTree(Random.nextInt(0, CANVAS_SIZE), Random.nextInt(0, CANVAS_SIZE),
+            "Summer Oak", Color.GREEN, "Oak texture stub")
+        forest.plantTree(Random.nextInt(0, CANVAS_SIZE), Random.nextInt(0, CANVAS_SIZE),
+            "Autumn Oak", Color.ORANGE, "Autumn Oak texture stub")
+    }
+    forest.setSize(CANVAS_SIZE, CANVAS_SIZE)
+    forest.isVisible = true
+    println("$TREES_TO_DRAW  trees drawn");
+    println("---------------------");
+    println("Memory usage:");
+    println("Tree size (8 bytes) * $TREES_TO_DRAW");
+    println("+ TreeTypes size (~30 bytes) * $TREE_TYPES");
+    println("---------------------");
+    println("Total: " + ((TREES_TO_DRAW * 8 + TREE_TYPES * 30) / 1024 / 1024) +
+            "MB (instead of " + ((TREES_TO_DRAW * 38) / 1024 / 1024) + "MB)");
+}