说明
模式定义: 组合模式(Composite Pattern)有时候又叫做部分-整体模式,用于将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性。
常见使用场景:如树形菜单、文件夹菜单、部门组织架构图等。
说到树形就需要先说说树的基本构成:
- 根节点
是树的一个组成部分,也叫树根。它是同一棵树中除本身外所有结点的祖先,没有父结点。
- 叶子结点
一棵树当中没有子结点(即度为0)的结点。 叶子是指度为0的结点,又称为终端结点。
- 子树
子树就是树的其中一个节点以及其下面的所有的节点所构成的树
组合模式结构说明
在组合模式中有三个角色, Component
、Leaf
、Composite
, 我们分别看一下
- Component
这是组合模式中对象声明的接口, 在适当情况下, 实现所有类共有的接口默认行为, 用于访问和管理Component
部件, Component
可以是抽象类或者接口。
- Leaf
在组合中表示叶子结点, 叶子结点没有子节点
- Composite
非叶子结点, 用于存储子部件, 在Component
接口中实现子部件的相关操作, 比如增加
示例
编写程序展示一个学校的院系结构,需求: 要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系
1. <?php 2. /** 3. *<?php /** * Created by 憧憬. */ abstract class OrganizationComponent { private $name; private $des; /** * OrganizationComponent constructor. * @param $name * @param $des */ public function __construct($name, $des) { $this->name = $name; $this->des = $des; } /** * @return mixed */ public function getName() { return $this->name; } /** * @param mixed $name */ public function setName($name): void { $this->name = $name; } /** * @return mixed */ public function getDes() { return $this->des; } /** * @param mixed $des */ public function setDes($des): void { $this->des = $des; } /** * 添加 * @param OrganizationComponent $organizationComponent * @throws Exception * @author: 憧憬 */ public function add(OrganizationComponent $organizationComponent) { throw new Exception('没有add'); } /** * 删除 * @param OrganizationComponent $organizationComponent * @throws Exception * @author: 憧憬 */ public function remove(OrganizationComponent $organizationComponent) { throw new Exception('没有remove'); } /** * 输出 * @return mixed * @author: 憧憬 */ abstract public function iprint(); } /** * 大学 * 是Composite角色, 可以管理College * Class University */ class University extends OrganizationComponent { public $organizationComponents; /** * University constructor. * @param $name * @param $des */ public function __construct($name, $des) { parent::__construct($name, $des); $this->organizationComponents = []; } public function add(OrganizationComponent $organizationComponent) { $this->organizationComponents[] = $organizationComponent; } public function remove(OrganizationComponent $organizationComponent) { foreach ($this->organizationComponents as $k => $component) { if ($component == $organizationComponent) { unset($this->organizationComponents[$k]); } } } public function getName() { return parent::getName(); // TODO: Change the autogenerated stub } public function getDes() { return parent::getDes(); // TODO: Change the autogenerated stub } /** * 输出University 包含的学院 * @return mixed|void * @author: 憧憬 */ public function iprint() { echo '---------------'. $this->getName() .'--------学校' . PHP_EOL; foreach ($this->organizationComponents as $component) { $component->iprint(); } } } /** * 学院 * Class College */ class College extends OrganizationComponent { // 包含的college public $organizationComponents; /** * University constructor. * @param $name * @param $des */ public function __construct($name, $des) { parent::__construct($name, $des); $this->organizationComponents = []; } public function add(OrganizationComponent $organizationComponent) { $this->organizationComponents[] = $organizationComponent; } public function remove(OrganizationComponent $organizationComponent) { foreach ($this->organizationComponents as $k => $component) { if ($component == $organizationComponent) { unset($this->organizationComponents[$k]); } } } public function getName() { return parent::getName(); // TODO: Change the autogenerated stub } public function getDes() { return parent::getDes(); // TODO: Change the autogenerated stub } /** * 输出University 包含的系 * @return mixed|void * @author: 憧憬 */ public function iprint() { echo '---------------'. $this->getName() .'-------学院' . PHP_EOL; foreach ($this->organizationComponents as $component) { $component->iprint(); } } } /** * 系 属于叶子结点 所以不需要重写add和remove * Class Department */ class Department extends OrganizationComponent { public function __construct($name, $des) { parent::__construct($name, $des); $this->organizationComponents = []; } public function iprint() { // TODO: Implement iprint() method. echo '-------------'.$this->getName(). '--------系'.PHP_EOL; } } // 创建学校 $university = new University('清华大学', '中国顶级大学'); // 创建学院 $computerCollege = new College('计算机学院', '计算机学院'); $infoEngineerCollege = new College('信息工程学院', '信息工程学院'); // 创建学院下的个个系 $computerCollege->add(new Department('软件工程', '软件工程ok')); $computerCollege->add(new Department('网络工程', '网络工程ok')); $computerCollege->add(new Department('计算机科学与技术', '计算机科学与技术ok')); $infoEngineerCollege->add(new Department('通信工程', '通信工程不ok')); $infoEngineerCollege->add(new Department('信息工程', '信息工程不ok')); // 将学院加入学校 $university->add($computerCollege); $university->add($infoEngineerCollege); // 输出整个大学下面的子节点 $university->iprint(); echo PHP_EOL; // 输出计算机学院下面的子节点 $computerCollege->iprint(); // 如果再要强化级别 只需要接着实现 组合进来就可以 比较方便 Created by 憧憬. 4. */ 5. 6. 7. abstract class OrganizationComponent { 8. private $name; 9. private $des; 10. 11. /** 12. * OrganizationComponent constructor. 13. * @param $name 14. * @param $des 15. */ 16. public function __construct($name, $des) 17. { 18. $this->name = $name; 19. $this->des = $des; 20. } 21. 22. /** 23. * @return mixed 24. */ 25. public function getName() 26. { 27. return $this->name; 28. } 29. 30. /** 31. * @param mixed $name 32. */ 33. public function setName($name): void 34. { 35. $this->name = $name; 36. } 37. 38. /** 39. * @return mixed 40. */ 41. public function getDes() 42. { 43. return $this->des; 44. } 45. 46. /** 47. * @param mixed $des 48. */ 49. public function setDes($des): void 50. { 51. $this->des = $des; 52. } 53. 54. 55. /** 56. * 添加 57. * @param OrganizationComponent $organizationComponent 58. * @throws Exception 59. * @author: 憧憬 60. */ 61. public function add(OrganizationComponent $organizationComponent) 62. { 63. throw new Exception('没有add'); 64. } 65. 66. 67. /** 68. * 删除 69. * @param OrganizationComponent $organizationComponent 70. * @throws Exception 71. * @author: 憧憬 72. */ 73. public function remove(OrganizationComponent $organizationComponent) 74. { 75. throw new Exception('没有remove'); 76. } 77. 78. 79. /** 80. * 输出 81. * @return mixed 82. * @author: 憧憬 83. */ 84. abstract public function iprint(); 85. } 86. 87. 88. /** 89. * 大学 90. * 是Composite角色, 可以管理College 91. * Class University 92. */ 93. class University extends OrganizationComponent { 94. 95. public $organizationComponents; 96. 97. /** 98. * University constructor. 99. * @param $name 100. * @param $des 101. */ 102. public function __construct($name, $des) 103. { 104. parent::__construct($name, $des); 105. $this->organizationComponents = []; 106. } 107. 108. public function add(OrganizationComponent $organizationComponent) 109. { 110. $this->organizationComponents[] = $organizationComponent; 111. } 112. 113. public function remove(OrganizationComponent $organizationComponent) 114. { 115. foreach ($this->organizationComponents as $k => $component) { 116. if ($component == $organizationComponent) { 117. unset($this->organizationComponents[$k]); 118. } 119. } 120. } 121. 122. public function getName() 123. { 124. return parent::getName(); // TODO: Change the autogenerated stub 125. } 126. 127. public function getDes() 128. { 129. return parent::getDes(); // TODO: Change the autogenerated stub 130. } 131. 132. /** 133. * 输出University 包含的学院 134. * @return mixed|void 135. * @author: 憧憬 136. */ 137. public function iprint() 138. { 139. echo '---------------'. $this->getName() .'--------学校' . PHP_EOL; 140. 141. foreach ($this->organizationComponents as $component) { 142. $component->iprint(); 143. } 144. } 145. 146. } 147. 148. 149. /** 150. * 学院 151. * Class College 152. */ 153. class College extends OrganizationComponent { 154. 155. // 包含的college 156. public $organizationComponents; 157. 158. /** 159. * University constructor. 160. * @param $name 161. * @param $des 162. */ 163. public function __construct($name, $des) 164. { 165. parent::__construct($name, $des); 166. $this->organizationComponents = []; 167. } 168. 169. public function add(OrganizationComponent $organizationComponent) 170. { 171. $this->organizationComponents[] = $organizationComponent; 172. } 173. 174. public function remove(OrganizationComponent $organizationComponent) 175. { 176. foreach ($this->organizationComponents as $k => $component) { 177. if ($component == $organizationComponent) { 178. unset($this->organizationComponents[$k]); 179. } 180. } 181. } 182. 183. public function getName() 184. { 185. return parent::getName(); // TODO: Change the autogenerated stub 186. } 187. 188. public function getDes() 189. { 190. return parent::getDes(); // TODO: Change the autogenerated stub 191. } 192. 193. /** 194. * 输出University 包含的系 195. * @return mixed|void 196. * @author: 憧憬 197. */ 198. public function iprint() 199. { 200. echo '---------------'. $this->getName() .'-------学院' . PHP_EOL; 201. 202. foreach ($this->organizationComponents as $component) { 203. $component->iprint(); 204. } 205. } 206. 207. } 208. 209. 210. /** 211. * 系 属于叶子结点 所以不需要重写add和remove 212. * Class Department 213. */ 214. class Department extends OrganizationComponent { 215. 216. 217. public function __construct($name, $des) 218. { 219. parent::__construct($name, $des); 220. $this->organizationComponents = []; 221. } 222. 223. 224. public function iprint() 225. { 226. // TODO: Implement iprint() method. 227. echo '-------------'.$this->getName(). '--------系'.PHP_EOL; 228. } 229. 230. } 231. 232. // 创建学校 233. $university = new University('清华大学', '中国顶级大学'); 234. 235. // 创建学院 236. $computerCollege = new College('计算机学院', '计算机学院'); 237. $infoEngineerCollege = new College('信息工程学院', '信息工程学院'); 238. 239. 240. 241. // 创建学院下的个个系 242. $computerCollege->add(new Department('软件工程', '软件工程ok')); 243. $computerCollege->add(new Department('网络工程', '网络工程ok')); 244. $computerCollege->add(new Department('计算机科学与技术', '计算机科学与技术ok')); 245. $infoEngineerCollege->add(new Department('通信工程', '通信工程不ok')); 246. $infoEngineerCollege->add(new Department('信息工程', '信息工程不ok')); 247. 248. // 将学院加入学校 249. $university->add($computerCollege); 250. $university->add($infoEngineerCollege); 251. 252. 253. // 输出整个大学下面的子节点 254. $university->iprint(); 255. 256. echo PHP_EOL; 257. 258. // 输出计算机学院下面的子节点 259. $computerCollege->iprint(); 260. 261. // 如果再要强化级别 只需要接着实现 组合进来就可以 比较方便