{"id":277,"date":"2020-04-21T19:59:14","date_gmt":"2020-04-21T10:59:14","guid":{"rendered":"http:\/\/batmask.dothome.co.kr\/?p=277"},"modified":"2021-07-16T01:37:49","modified_gmt":"2021-07-15T16:37:49","slug":"design-pattern-composite","status":"publish","type":"post","link":"http:\/\/batmask.net\/index.php\/2020\/04\/21\/277\/","title":{"rendered":"Design Pattern: Composite"},"content":{"rendered":"\n<p>\uc720\uc0ac\ud55c \uc544\uc774\ud15c\ub4e4\uc744 \ud2b8\ub9ac\uad6c\uc870\ub85c \uad6c\uc131\ud574\uc57c\ud560 \ub54c, \ucee8\ud14c\uc774\ub108 \ub178\ub4dc\uc640 \ucef4\ud3ec\ub10c\ud2b8\ub178\ub4dc\ub4e4\uc758 \uc778\ud130\ud398\uc774\uc2a4\ub97c \ud1b5\uc77c\uc2dc\ucf1c\uc900\ub2e4. \uc774\ub807\uac8c\ud558\uba74, \ucee8\ud14c\uc774\ub108\uc640 \ucef4\ud3ec\ub10c\ud2b8\ub97c \uad6c\ubcc4\ud560 \ud544\uc694\uac00 \uc5c6\uc5b4\uc838\uc11c \ucee8\ud14c\uc774\ub108 \uc548\uc5d0 \ub2e4\ub978 \ucee8\ud14c\uc774\ub108\ub3c4 \ud3ec\ud568\uac00\ub2a5\ud574\uc9c4\ub2e4. \ub610\ud55c \uc778\ud130\ud398\uc774\uc2a4\uc5d0 \uc815\uc758\ub41c \uae30\ub2a5\uc744 \uc2e4\ud589\uc2dc, \ud2b8\ub9ac\uad6c\uc870\uc0c1\uc758 \ud558\uc704 \uc804\uccb4\uc5d0 \uc27d\uac8c \uc2e4\ud589\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p> \uc774\ud574\uac00 \uc26c\uc6b4 \uc2e4\uc81c \uc608\ub4e4\uc774 \uc544\uc8fc \ub9ce\ub2e4. \ub514\ub809\ud1a0\ub9ac \ud30c\uc77c\uad6c\uc870\ub97c \uc0dd\uac01\ud574\ubcf4\uba74, \ub514\ub809\ud1a0\ub9ac\uc548\uc5d0 \ub2e4\ub978 \ub514\ub809\ud1a0\ub9ac\uac00 \uc62c \uc218 \uc788\uace0, rename, delete\ub4f1\uc758 \uae30\ub2a5\ub4e4\uc744 \uc778\ud130\ud398\uc774\uc2a4\ub85c \uc815\uc758\ud558\uba74 \ub41c\ub2e4\ub294\uac78 \uc54c \uc218 \uc788\uc744\uac83\uc774\ub2e4.<\/p>\n\n\n\n<p>\ub610 \ub2e4\ub978 \uc608\ub294 \uadf8\ub798\ud53d \ud234\ub4e4\uc744 \ubcfc \uc218 \uc788\ub2e4. \uadf8\ub798\ud53d \uc624\ube0c\uc81d\ud2b8\ub4e4\uc740 \uac00\uc7a5 \uc9c1\uad00\uc801\uc778 OOP\uc5d0 \ud574\ub2f9\ud558\ub294\ub370, \uc774\ub4e4\uc744 \uadf8\ub8f9\uc73c\ub85c \ubb36\uc5b4 \uc774\ub3d9\ud558\uac70\ub098 \ud06c\uae30\ub97c \ubcc0\uacbd\ud558\ub294\ub4f1\uc758 \uc77c\uc774 \uac00\ub2a5\ud558\ub2e4. \uc774\ub97c composite \ud328\ud134\uc73c\ub85c \uad6c\ud604\ud558\ub294\uac74 \ub9e4\uc6b0 \uc9c1\uad00\uc801\uc774\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"333\" height=\"306\" src=\"http:\/\/batmask.dothome.co.kr\/wordpress\/wp-content\/uploads\/2020\/04\/blender_collection.png\" alt=\"\" class=\"wp-image-441\" srcset=\"http:\/\/batmask.net\/wordpress\/wp-content\/uploads\/2020\/04\/blender_collection.png 333w, http:\/\/batmask.net\/wordpress\/wp-content\/uploads\/2020\/04\/blender_collection-300x276.png 300w\" sizes=\"auto, (max-width: 333px) 100vw, 333px\" \/><figcaption>Blender 2.8 Collections<\/figcaption><\/figure><\/div>\n\n\n\n<p>\uc704\uc758 \uc774\ubbf8\uc9c0\ub294 \uc624\ud508\uc18c\uc2a4 3D \ubaa8\ub378\ub9c1\ud234\uc778 Blender\uc758 Collection \uc708\ub3c4\uc6b0 \ubaa8\uc2b5\uc774\ub2e4. \ubaa8\ub378\ub9c1\uc73c\ub85c \uc0dd\uc131\ud55c \uc5ec\ub7ec \uc624\ube0c\uc81d\ud2b8\ub4e4\uc744 Collection\uc774\ub780 \ud2b8\ub9ac\uad6c\uc870\ub85c \uad00\ub9ac\ud560 \uc218 \uc788\ub2e4. \uc774\ub7f0 \uac83\ub4e4\uc744 \ub9cc\ub4e4 \ub54c composite pattern\uc774 \uc0ac\uc6a9\ub420 \uac83\uc774\ub2e4.<\/p>\n\n\n\n<p> \ud558\ub098\ub9cc \uc608\ub97c \ub354 \ub4e4\uc790\uba74, \ud68c\uc0ac\uc758 \uc870\uc9c1\ub3c4\uc5d0 \ub530\ub978 \uc9c1\uc6d0 \uad00\ub9ac\ub2e4. \uc9c1\uc6d0\uacfc \uc9c1\ucc45\ub4e4\uc740 OOP\ub97c \ud45c\ud604\ud558\uae30\uc5d0 \uc9c1\uad00\uc801\uc774\ub77c\uc11c \uc608\uc2dc\ub85c \ub9ce\uc774 \ub098\uc624\ub294\ub370, \uc5ec\uae30\uc11c\ub3c4 \uadf8\ub807\ub2e4. \uc9c1\uc6d0\ub4e4\uc758 \ucee8\ud14c\uc774\ub108\uac00 \ubd80\uc11c\uc5d0 \ud574\ub2f9\ud55c\ub2e4.  composite \ud328\ud134\uc73c\ub85c \uad6c\ud604\ud558\uba74, \ubd80\uc11c \uc804\uccb4\uc5d0 \ud3ec\uc0c1\uc744 \ud558\uac70\ub098, \ud558\uc704\ubd80\uc11c \uc804\uccb4\ub97c \uc774\ub3d9\ud558\ub294\ub4f1\uc758 \uc791\uc5c5\uc774 \uc6a9\uc774\ud574\uc9c4\ub2e4.<\/p>\n\n\n\n<p>design pattern\uc790\uccb4\uc758 \ubaa9\uc801\ub3c4 \uba85\ud655\ud558\uace0 \uc774\ud574\ud558\uae30 \uc5b4\ub835\uc9c4 \uc54a\ub2e4. \uc774\ub97c UML\ub85c \ud45c\ud604\ud558\uba74 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"240\" src=\"http:\/\/batmask.dothome.co.kr\/wordpress\/wp-content\/uploads\/2020\/04\/W3sDesign_Composite_Design_Pattern_UML.jpg\" alt=\"\" class=\"wp-image-443\" srcset=\"http:\/\/batmask.net\/wordpress\/wp-content\/uploads\/2020\/04\/W3sDesign_Composite_Design_Pattern_UML.jpg 600w, http:\/\/batmask.net\/wordpress\/wp-content\/uploads\/2020\/04\/W3sDesign_Composite_Design_Pattern_UML-300x120.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><figcaption>Composite pattern UML ( <a href=\"https:\/\/en.wikipedia.org\/wiki\/Composite_pattern\">\uc704\ud0a4\ud53c\ub514\uc544 \ucc38\uc870 <\/a>)<\/figcaption><\/figure>\n\n\n\n<hr class=\"wp-block-separator is-style-dots\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Kotlin<\/h3>\n\n\n\n<p> \uad6c\ud604\uc744 \ud574\ubcf4\uc790. \uc55e\uc5d0\uc11c \ubd24\ub358 Blender\uc758 Collection\uc744 \uac04\ub2e8\ud558\uac8c\ub9cc \ud749\ub0b4\ub0b4 \ubcf4\uaca0\ub2e4.<\/p>\n\n\n\n<pre title=\"Collections.kt\" class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">package composite\n\ndata class Position(var x: Double = 0.0, var y: Double = 0.0, var z: Double = 0.0)\n\nabstract class CollectionComponent(name: String, pos: Position) {\n    var componentName = name\n    var position: Position = pos\n    abstract fun getCollection(): CollectionComposite?\n\n    abstract fun move(delta: Position)\n    abstract fun scale(factor: Double)\n\n}\n\nclass CollectionComposite(name: String, pos: Position): CollectionComponent(name, pos) {\n    private var leafs: MutableList&lt;CollectionComponent> = mutableListOf()\n\n    override fun getCollection(): CollectionComposite? {\n        return this\n    }\n\n    override fun move(delta: Position) {\n        \/\/ iterate sub tree\n        for(component in leafs){\n            component.move(delta)\n        }\n    }\n\n    override fun scale(factor: Double) {\n        \/\/ iterate sub tree\n        for(component in leafs){\n            component.scale(factor)\n        }\n    }\n\n    fun addComponent(component: CollectionComponent){\n        leafs.add(component)\n    }\n    fun deleteComponent(component: CollectionComponent){\n        leafs.remove(component)\n    }\n\n    fun getChilds(): List&lt;CollectionComponent>{\n        return leafs\n    }\n}\n\nclass ObjectLeaf(name: String, pos: Position): CollectionComponent(name, pos) {\n\n    override fun getCollection(): CollectionComposite? {\n        return null\n    }\n\n    override fun move(delta: Position) {\n        position.x += delta.x\n        position.y += delta.y\n        position.z += delta.z\n        println(\"move $componentName : $position\")\n    }\n\n    override fun scale(factor: Double) {\n        println(\"scale $componentName : $factor\")\n    }\n\n}<\/code><\/pre>\n\n\n\n<p>UML\uacfc \ub9e4\uce6d\uc2dc\ud0a4\uae30 \uc704\ud574 \uc758\ub3c4\uc801\uc73c\ub85c \uc774\ub984\uc5d0 Component, Composite, Leaf\ub97c \ub123\uc5c8\ub2e4. composite\uc5d0\ub9cc \uc788\ub294 add, delete \uba54\uc18c\ub4dc\ub294 Component\uc5d0\uc11c abstract\ub85c \ub9cc\ub4e4\uace0 Leaf\uc5d0 \ub3d9\uc791\ud558\uc9c0 \uc54a\ub294 \uad6c\ud604\uc744 \ucd94\uac00\ud560\uc218\ub3c4 \uc788\uc73c\ub098, \uc5ec\uae30\uc11c\ub294 getCollection \uba54\uc18c\ub4dc\ub97c \ub9cc\ub4e4\uc5b4\uc11c null\uc774 \uc544\ub2c8\uba74 composite \uac1d\uccb4\ub85c \uce90\uc2a4\ud305\ud574\uc11c \uc0ac\uc6a9\ud560 \uc218 \uc788\uac8c\ud588\ub2e4.<\/p>\n\n\n\n<pre title=\"Client.kt\" class=\"wp-block-code\"><code lang=\"kotlin\" class=\"language-kotlin\">package composite\n\n\nfun main(args: Array&lt;String>){\n    val collection1: CollectionComponent = CollectionComposite(\"Collection1\", Position(1.0, 1.0, 1.0))\n    val cylinder: CollectionComponent = ObjectLeaf(\"Cylinder\", Position(0.0, 0.0, 0.0))\n    val collection2: CollectionComponent = CollectionComposite(\"Collection2\", Position(0.0, 0.0, 0.0))\n    val box: CollectionComponent = ObjectLeaf(\"Box\", Position(0.0, 0.0, 0.0))\n    val camera: CollectionComponent = ObjectLeaf(\"Camera\", Position(10.0, 10.0, 3.0))\n    val light: CollectionComponent = ObjectLeaf(\"Light\", Position(15.0, 10.0, 13.0))\n\n    val composite2 = collection2.getCollection() as CollectionComposite\n    composite2.addComponent(camera)\n    composite2.addComponent(light)\n    composite2.addComponent(box)\n    for(component in composite2.getChilds()) println(component.componentName)\n    println(\"\")\n    val composite1 = collection1.getCollection() as CollectionComposite\n    composite1.addComponent(cylinder)\n    composite1.addComponent(composite2)\n    for(component in composite1.getChilds()) println(component.componentName)\n\n    println(\"\")\n    box.move(Position(2.0, 2.0, 2.0))\n    println(\"\")\n    composite1.move(Position(1.0, 1.0, 1.0))\n}<\/code><\/pre>\n\n\n\n<pre title=\"Output\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">Camera\nLight\nBox\n\nCylinder\nCollection2\n\nmove Box : Position(x=2.0, y=2.0, z=2.0)\n\nmove Cylinder : Position(x=1.0, y=1.0, z=1.0)\nmove Camera : Position(x=11.0, y=11.0, z=4.0)\nmove Light : Position(x=16.0, y=11.0, z=14.0)\nmove Box : Position(x=3.0, y=3.0, z=3.0)\n<\/code><\/pre>\n\n\n\n<p>Component\ub2e8\uc5d0\uc11c \uc778\ud130\ud398\uc774\uc2a4\ub85c \ub9cc\ub4e4\uc5b4\ub193\uc740 move, scale \uba54\uc18c\ub4dc\ub294 composite\uc5d0 \uc0ac\uc6a9\ub420 \uacbd\uc6b0, iteration\ud558\uba70 \ud558\uc704\ud2b8\ub9ac \ubaa8\ub4e0 \uac1d\uccb4\uac00 \uc801\uc6a9\ub418\ub294\uac78 \ubcfc \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p>Composite\uc5d0 \uc788\ub294 delete\uc5d0 \ub300\ud55c \uace0\ubbfc\uc744 \uc880 \ud588\uc5c8\ub294\ub370, \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\ub294\uac74 client\uc5d0\uc11c \ud558\uace0 add\ub294 \ub2e8\uc9c0 \ub808\ud37c\ub7f0\uc2a4\ub97c \ucd94\uac00\ud558\ub294 \uc791\uc5c5\uc774\uae30 \ub54c\ubb38\uc5d0 \uc5ec\uae30\uc5d0\uc11c\uc758 delete\ub294 \ub808\ud37c\ub7f0\uc2a4\ub9cc \uc81c\uac70\ud558\uace0 \uc788\ub2e4. \ub9cc\uc57d, \uac1d\uccb4\uc758 \uc0ad\uc81c\ub97c \uace0\ub824\ud55c\ub2e4\uba74 move, scale\ucc98\ub7fc sub tree\uc5d0 \uc804\ubd80 \uc801\uc6a9\ub420 \uc218 \uc788\ub3c4\ub85d \uace0\ubbfc\uc774 \ud544\uc694\ud558\ub2e4. <\/p>\n\n\n\n<p>\ud575\uc2ec\uc740 \ud2b8\ub9ac\ud615\ud0dc\ub85c \uad6c\uc131\uc744 \ud560 \uc218 \uc788\uace0 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c \uadf8 \uad6c\uc131\uc774\ub098 \uc544\uc774\ud15c\uc5d0 \ub300\ud574 \ubab0\ub77c\ub3c4 \ud558\ub098\uc758 component\uc5d0 \ub300\ud574 move() \ub098 scale()\uc744 \ud638\ucd9c\ud558\uba74 sub-tree\uae4c\uc9c0 \uc804\ubd80 \uc801\uc6a9\ub420 \uc218 \uc788\ub2e4\ub294 \uc810\uc774\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-dots\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">C#<\/h3>\n\n\n\n<pre title=\"ObjCollections.cs\" class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\nnamespace Composite\n{\n    public abstract class CollectionComponent\n    {\n        string _name;\n        Vector3 _position;\n\n        public string Name\n        {\n            get => _name;\n            set => _name = value;\n        }\n\n        public Vector3 Position\n        {\n            get => _position;\n            set => _position = value;\n        }\n\n\n        public CollectionComponent(string name, Vector3 pos)\n        {\n            Name = name;\n            Position = pos;\n        }\n\n        abstract public CollectionComposite GetComposite();\n        abstract public void Move(Vector3 delta);\n        abstract public void Scale(double factor);\n    }\n\n    public class CollectionComposite: CollectionComponent\n    {\n        private List&lt;CollectionComponent> leafs = new List&lt;CollectionComponent>();\n\n        public CollectionComposite(string name, Vector3 pos): base(name, pos)\n        {\n            \n        }\n\n        public override CollectionComposite GetComposite()\n        {\n            return this;\n        }\n\n        public override void Move(Vector3 delta)\n        {\n            foreach(var leaf in leafs)\n            {\n                leaf.Move(delta);\n            }\n        }\n\n        public override void Scale(double factor)\n        {\n            foreach(var leaf in leafs)\n            {\n                leaf.Scale(factor);\n            }\n        }\n\n        public void AddComponent(CollectionComponent comp)\n        {\n            leafs.Add(comp);\n        }\n\n        public void deleteComponent(CollectionComponent comp)\n        {\n            leafs.Remove(comp);\n        }\n\n        public List&lt;CollectionComponent> GetChilds()\n        {\n            return leafs;\n        }\n    }\n\n    public class ObjectLeaf: CollectionComponent\n    {\n        public ObjectLeaf(string name, Vector3 pos): base(name, pos)\n        {\n\n        }\n\n        public override CollectionComposite GetComposite()\n        {\n            return null;\n        }\n\n        public override void Move(Vector3 delta)\n        {\n            Position = Position + delta;\n            Debug.Log(\"Move \" + Name + \", \" + Position);\n        }\n\n        public override void Scale(double factor)\n        {\n            Debug.Log(\"Scale \" + Name + \", \" + factor);\n        }\n    }\n\n}\n<\/code><\/pre>\n\n\n\n<p> C# 7.0\ubd80\ud130 \uc801\uc6a9\ub41c property\uc758 \uac04\ub2e8\ud55c \uc0ac\uc6a9\ubc95\uc744 \uc801\uc6a9\ud588\ub2e4. C#\uc5d0\uc120 super \ud0a4\uc6cc\ub4dc\uac00 \uc5c6\uace0 base \ud0a4\uc6cc\ub4dc\ub97c \uc4f4\ub2e4. \uc11c\ube0c\ud074\ub798\uc2a4 \uc0dd\uc131\uc790\uc5d0\uc11c base()\uc0dd\uc131\uc790\ub85c \uc778\uc790\ub4e4\uc744 \uc804\ub2ec\ud558\uace0 \uc788\ub2e4. Kotlin\uc5d0\uc11c\ub294 \uc5c6\uc5b4\uc11c Postion\uc774\ub780 \uc720\uc0ac\ud074\ub798\uc2a4\ub97c \ub9cc\ub4e4\uc5b4 \uc37c\ub294\ub370, \uc720\ub2c8\ud2f0\uc5d0\uc11c \uae30\ubcf8\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 Vector3\uac00 \uc788\uc73c\ubbc0\ub85c \uc774\ub97c \uc0ac\uc6a9\ud588\ub2e4. Kotlin\uc774\ub098 Python\uc5d0\uc11c \uc775\uc219\ud55c for\ubb38\uc740 C#\uc5d0\uc11c\ub294 foreach\uc5d0 \ud574\ub2f9\ud55c\ub2e4. for\ubb38\uc740 C\/C++\uacfc \uac19\uc740 \uc61b\ub0a0 \ud3ec\ub9f7\uc744 \uac16\ub294\ub2e4.<\/p>\n\n\n\n<pre title=\"Client.cs\" class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\nnamespace Composite\n{\n    public class Client : MonoBehaviour\n    {\n        \/\/ Start is called before the first frame update\n        void Start()\n        {\n            CollectionComponent collection1 = new CollectionComposite(\"Collection1\", Vector3.zero);\n            CollectionComponent cylinder = new ObjectLeaf(\"Cylinder\", new Vector3(0, 0, 0));\n            CollectionComponent collection2 = new CollectionComposite(\"Collection2\", Vector3.zero);\n            CollectionComponent box = new ObjectLeaf(\"Box\", new Vector3(0, 0, 0));\n            CollectionComponent camera = new ObjectLeaf(\"Camera\", new Vector3(10, 10, 3));\n            CollectionComponent light = new ObjectLeaf(\"Light\", new Vector3(15, 10, 13));\n\n            CollectionComposite composite = collection2.GetComposite();\n            composite.AddComponent(camera);\n            composite.AddComponent(light);\n            composite.AddComponent(box);\n\n            foreach(var item in composite.GetChilds())\n            {\n                Debug.Log(item.Name);\n            }\n\n            composite = collection1.GetComposite();\n            composite.AddComponent(cylinder);\n            composite.AddComponent(collection2);\n\n            foreach (var item in composite.GetChilds())\n            {\n                Debug.Log(item.Name);\n            }\n\n            box.Move(new Vector3(2, 2, 2));\n            composite.Scale(1.3);\n\n        }\n\n    }\n\n}\n<\/code><\/pre>\n\n\n\n<p>\ud074\ub77c\uc774\uc5b8\ud2b8 \ucf54\ub4dc\ub294 Kotlin\uacfc \uac70\uc758 \uac19\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"542\" height=\"387\" src=\"http:\/\/batmask.dothome.co.kr\/wordpress\/wp-content\/uploads\/2020\/04\/composite_output.png\" alt=\"\" class=\"wp-image-452\" srcset=\"http:\/\/batmask.net\/wordpress\/wp-content\/uploads\/2020\/04\/composite_output.png 542w, http:\/\/batmask.net\/wordpress\/wp-content\/uploads\/2020\/04\/composite_output-300x214.png 300w\" sizes=\"auto, (max-width: 542px) 100vw, 542px\" \/><\/figure><\/div>\n\n\n\n<p>\uc720\ub2c8\ud2f0\uc5d0\uc11c \ub85c\uadf8\ub97c \ud544\uc694\ud55c\uac83\ub9cc \uae54\ub054\ud558\uac8c \ud14d\uc2a4\ud2b8\ub85c \ubf51\uc544\ub0b4\ub294\uac78 \uc798 \ubaa8\ub974\uaca0\ub2e4. <\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-dots\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Python<\/h3>\n\n\n\n<pre title=\"Component.py\" class=\"wp-block-code\"><code lang=\"python\" class=\"language-python\">from dataclasses import dataclass\nfrom typing import List\n\n@dataclass\nclass Position:\n    x: float = 0\n    y: float = 0\n    z: float = 0\n\n    def __add__(self, pos):\n        return Position(self.x + pos.x, self.y + pos.y, self.z + pos.z)\n\n    def __iadd__(self, pos):\n        self.x += pos.x\n        self.y += pos.y\n        self.z += pos.z\n        return self\n\n\nclass Component:\n    def __init__(self, name: str, pos: Position):\n        self._name: str = name\n        self._position: Position = pos\n\n    @property\n    def name(self):\n        return self._name\n\n    @name.setter\n    def name(self, value: Position):\n        self._name = value\n\n    @property\n    def position(self):\n        return self._position\n\n    @position.setter\n    def position(self, value: Position):\n        self._position = value\n\n    def get_composite(self):\n        raise NotImplementedError\n\n    def move(self, delta: Position):\n        raise NotImplementedError\n\n    def scale(self, factor: float):\n        raise NotImplementedError\n\nclass Composite(Component):\n    def __init__(self, name: str, pos: Position):\n        super().__init__(name, pos)\n        self._leafs: List[Component] = []\n\n    def get_composite(self):\n        return self\n\n    def move(self, delta: Position):\n        for leaf in self._leafs:\n            leaf.move(delta)\n\n    def scale(self, factor: float):\n        for leaf in self._leafs:\n            leaf.scale(factor)\n\n    def add_component(self, comp: Component):\n        self._leafs.append(comp)\n\n    def remove_component(self, comp: Component):\n        self._leafs.remove(comp)\n\n    def get_childs(self) -> List[Component]:\n        return self._leafs\n\nclass Leaf(Component):\n    def __init__(self, name: str, pos: Position):\n        super().__init__(name, pos)\n\n    def get_composite(self):\n        return None\n\n    def move(self, delta: Position):\n        self.position += delta\n        print(f\"{self.name} move {self.position}\")\n\n    def scale(self, factor: float):\n        print(f\"{self.name} scale : {factor}\")\n\n<\/code><\/pre>\n\n\n\n<p>Vector\ub97c \ud749\ub0b4\ub0b4\ub294 \uac04\ub2e8\ud55c dataclass\ub85c Position\uc744 \ub9cc\ub4e4\uc5c8\ub2e4. \uc5f0\uc0b0\uc790 \uc624\ubc84\ub85c\ub529\uc744 \uc704\ud574, \ube4c\ud2b8\uc778 \ud568\uc218\uc778  __add__(self, other), __iadd__(self, other) \ub97c \uc624\ubc84\ub85c\ub529\ud588\ub2e4. __iadd__\ub294 &#8216;+=&#8217; \uc5f0\uc0b0\uc790\uc5d0 \ud574\ub2f9\ud55c\ub2e4.<\/p>\n\n\n\n<p>\ud074\ub798\uc2a4 \uc774\ub984\ub4e4\uc740 \uc55e\uc5d0\uc11c\uc640 \ub2ec\ub9ac \ud3b8\uc758\uc0c1 Component, Composite, Leaf\ub85c \ub9cc\ub4e4\uc5c8\ub2e4. property\ub294 python\uc758 \ubc29\ubc95\uc73c\ub85c \ucc98\ub9ac\ub418\ub294\uac78 \ubcfc \uc218 \uc788\ub2e4. backing field\ub294 private\uc5d0 \ud574\ub2f9\ud558\ub294 &#8216;_&#8217;\ub97c \ubd99\uc5ec\uc11c \uc678\ubd80\uc5d0\uc11c \uc5d1\uc138\uc2a4\uac00 \ubd88\uac00\ud558\uac8c \ub9cc\ub4e4\uc5c8\ub2e4. abstract method\ub4e4\uc740 abs \ubaa8\ub4c8\uc744 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uace0 \uac04\ub2e8\ud558\uac8c \uc608\uc678\ub97c \ubc1c\uc0dd\uc2dc\ud0a4\ub3c4\ub85d \ud588\ub2e4.<\/p>\n\n\n\n<pre title=\"Client.py\" class=\"wp-block-code\"><code lang=\"python\" class=\"language-python\">from composite.Component import *\n\ndef main():\n    collection1 = Composite(\"Collection1\", Position(1, 1, 1))\n    cylinder = Leaf(\"Cylinder\", Position(0, 0, 0))\n    collection2 = Composite(\"Collection2\", Position(0, 0, 0))\n    box = Leaf(\"Box\", Position(0, 0, 0))\n    camera = Leaf(\"Camera\", Position(10, 10, 3))\n    light = Leaf(\"Light\", Position(15, 10, 13))\n\n    collection2.add_component(camera)\n    collection2.add_component(light)\n    collection2.add_component(box)\n    for item in collection2.get_childs():\n        print(item.name)\n\n    collection1.add_component(cylinder)\n    collection1.add_component(collection2)\n    for item in collection1.get_childs():\n        print(item.name)\n\n    box.move(Position(2, 2, 2))\n    collection1.scale(1.3)\n\n\nif __name__ == \"__main__\":\n    main()\n\n<\/code><\/pre>\n\n\n\n<pre title=\"Output\" class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">Camera\nLight\nBox\nCylinder\nCollection2\nBox move Position(x=2, y=2, z=2)\nCylinder scale : 1.3\nCamera scale : 1.3\nLight scale : 1.3\nBox scale : 1.3<\/code><\/pre>\n\n\n\n<p>\ud074\ub77c\uc774\uc5b8\ud2b8 \ucf54\ub4dc\ub294 \uc55e\uc5d0\uc11c\uc640 \ud06c\uac8c \ub2e4\ub974\uc9c0 \uc54a\uc740\ub370, dynamic type\uc5b8\uc5b4\uc774\uae30\uc5d0 \uad73\uc774 component \ud0c0\uc785\uc744 annotation\uc73c\ub85c \ucd94\uac00\ud558\uc9c0 \uc54a\uc558\ub2e4. \uce90\uc2a4\ud305\uc5c6\uc774 \uc790\uc5f0\uc2a4\ub7fd\uac8c \uc0ac\uc6a9\uac00\ub2a5\ud558\ub2e4. <\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-dots\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion<\/h3>\n\n\n\n<p>\uc5ec\ub7ec\uac00\uc9c0 \uc5b8\uc5b4\ub85c \uad6c\ud604\ud574\ubcf4\uba74\uc11c \uc88b\uc740\uc810\uc740, \ubc18\ubcf5\uc791\uc5c5\uc911\uc5d0 \ud328\ud134\uc5d0\ub300\ud55c \uc774\ud574\ub3c4\uac00 \ub192\uc544\uc9c4\ub2e4\ub294 \uc810\uc774\ub2e4. composite pattern\uc73c\ub85c \uad6c\ud604\ud574\ub193\uc73c\ub2c8 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c move(), scale() \uc0ac\uc6a9\uc774 \ub108\ubb34\ub098\ub3c4 \ud3b8\ud574\uc9c4\uac78 \ub290\uaf08\ub2e4. \uc774 \uc9c0\uc810\uc774 \ubc14\ub85c composite pattern\uc758 \ud575\uc2ec\uc774\ub77c\uace0 \ubcf4\uc5ec\uc9c4\ub2e4. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>\uc720\uc0ac\ud55c \uc544\uc774\ud15c\ub4e4\uc744 \ud2b8\ub9ac\uad6c\uc870\ub85c \uad6c\uc131\ud574\uc57c\ud560 \ub54c, \ucee8\ud14c\uc774\ub108 \ub178\ub4dc\uc640 \ucef4\ud3ec\ub10c\ud2b8\ub178\ub4dc\ub4e4\uc758 \uc778\ud130\ud398\uc774\uc2a4\ub97c \ud1b5\uc77c\uc2dc\ucf1c\uc900\ub2e4. \uc774\ub807\uac8c\ud558\uba74, \ucee8\ud14c\uc774\ub108\uc640 \ucef4\ud3ec\ub10c\ud2b8\ub97c \uad6c\ubcc4\ud560 \ud544\uc694\uac00 \uc5c6\uc5b4\uc838\uc11c \ucee8\ud14c\uc774\ub108 \uc548\uc5d0 \ub2e4\ub978 \ucee8\ud14c\uc774\ub108\ub3c4 \ud3ec\ud568\uac00\ub2a5\ud574\uc9c4\ub2e4. \ub610\ud55c \uc778\ud130\ud398\uc774\uc2a4\uc5d0 \uc815\uc758\ub41c \uae30\ub2a5\uc744 \uc2e4\ud589\uc2dc, \ud2b8\ub9ac\uad6c\uc870\uc0c1\uc758 \ud558\uc704 \uc804\uccb4\uc5d0 \uc27d\uac8c \uc2e4\ud589\ud560 \uc218 \uc788\ub2e4. \uc774\ud574\uac00 \uc26c\uc6b4 \uc2e4\uc81c \uc608\ub4e4\uc774 \uc544\uc8fc \ub9ce\ub2e4. \ub514\ub809\ud1a0\ub9ac \ud30c\uc77c\uad6c\uc870\ub97c \uc0dd\uac01\ud574\ubcf4\uba74, \ub514\ub809\ud1a0\ub9ac\uc548\uc5d0 \ub2e4\ub978 \ub514\ub809\ud1a0\ub9ac\uac00 \uc62c \uc218 \uc788\uace0, rename, delete\ub4f1\uc758 <a href=\"http:\/\/batmask.net\/index.php\/2020\/04\/21\/277\/\" class=\"btn btn-link continue-link\">\ub354 \uc77d\uae30<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,6,34,33],"tags":[],"class_list":["post-277","post","type-post","status-publish","format-standard","hentry","category-note4reference","category-unity","category-kotlin","category-python"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts\/277","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/comments?post=277"}],"version-history":[{"count":11,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts\/277\/revisions"}],"predecessor-version":[{"id":455,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/posts\/277\/revisions\/455"}],"wp:attachment":[{"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/media?parent=277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/categories?post=277"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/batmask.net\/index.php\/wp-json\/wp\/v2\/tags?post=277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}