组合模式针对于特定场景,如文件管理、组织管理等,使用该模式能简化管理,使代码变得非常简洁。
UML类图位置:https://www.processon.com/diagraming/609b375407912943913a4c13
本文代码链接为:https://github.com/shidawuhen/asap/blob/master/controller/design/16composite.go
1.定义
1.1组合模式
组合模式:将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
UML:
1.2分析
单看UML图可能不清晰,举个栗子会容易一些。Composite是目录,Leaf是目录下的文件,目录和文件都继承自Component。目录能够增加、删除文件,可以展示目录所在位置,文件只能展示文件所在位置。
对于目录这种需求,有两种实现方式。
第一种不使用组合模式,只用一个类,有2个核心变量
- 一个成员变量表明对象是文件还是目录
- 一个成员变量存放目录下文件列表,如果对象为文件,则该变量为空
1 | type FileSystemNode struct { |
第二种方案使用组合模式。虽然第一种方案能够实现文件管理的功能,但并不优雅。因为文件和目录是不同的,各自有各自的特性,将特有的内容放到一个类里,不满足单一职责原则。
所以我们可以将其拆分为两个类:文件类和目录类。两个类必须继承自同一个父类,除了重复的功能可以复用外,更重要的一点是消除了两个类调用上的区别,subNodes不需要做任何区分。而且这两个类可以独立进化,相互不影响,何乐而不为呢。
2.使用场景
组合模式在使用上,特别像深度优先遍历或者广度优先遍历,一般用于组织结构、文件管理上,这些功能都有共通点:个体和集体无论在功能上还是认知上都极为相似。
字节跳动的协同办公软件-飞书,在文档管理部分,就极其适合使用组合模式,大家有时间可以尝试一下,链接如下:https://www.feishu.cn/ ,其展现样式如下所示:
3.代码实现
这次代码简单实现一下目录和文件的添加、显示功能吧。
1 | package main |
显示:
➜ myproject go run main.go
–笔记
—-会议
——晨会.md 文件内容为:Hello,world
——周会.md 文件内容为:Hello,world
文件类和目录类都实现了FileSystemNode接口,所以目录类管理文件类如同管理自己一样。两者都组合了FileCommonFunc类,可以复用相同功能。最后就是两者可以独立变化,如目录类有Add功能,但文件类没有。
3.总结
组合模式是对指定场景有用,所以大家能不能用到,完全看运气。这个设计模式满足单一职责原则、开闭原则、里氏替换原则。