Go设计模式(16)-组合模式

组合模式针对于特定场景,如文件管理、组织管理等,使用该模式能简化管理,使代码变得非常简洁。

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个核心变量

  • 一个成员变量表明对象时文件还是目录
  • 一个成员变量存放目录下文件列表,如果对象为文件,则该变量为空
type FileSystemNode struct {
   isFile   bool             //表明是文件还是目录
   subNodes []FileSystemNode //目录下包含的内容
}

第二种方案使用组合模式。虽然第一种方案能够实现文件管理的功能,但并不优雅。因为文件和目录是不同的,各自有各自的特性,将特有的内容放到一个类里,不满足单一职责原则

所以我们可以将其拆分为两个类:文件类和目录类。两个类必须继承自同一个父类,除了重复的功能可以复用外,更重要的一点是消除了两个类调用上的区别,subNodes不需要做任何区分。而且这两个类可以独立进化,相互不影响,何乐而不为呢。

2.使用场景

组合模式在使用上,特别像深度优先遍历或者广度优先遍历,一般用于组织结构、文件管理上,这些功能都有共通点:个体和集体无论在功能上还是认知上都极为相似。

字节跳动的协同办公软件-飞书,在文档管理部分,就极其适合使用组合模式,大家有时间可以尝试一下,链接如下:https://www.feishu.cn/ ,其展现样式如下所示:
在这里插入图片描述

3.代码实现

这次代码简单实现一下目录和文件的添加、显示功能吧。

package main

import "fmt"

const Separator = "--"

/**
 * @Author: Jason Pang
 * @Description: 文件系统接口,文件和目录都要实现该接口
 */
type FileSystemNode interface {
   Display(separator string)
}

/**
 * @Author: Jason Pang
 * @Description: 文件通用功能
 */
type FileCommonFunc struct {
   fileName string
}

/**
 * @Author: Jason Pang
 * @Description: 设置文件名称
 * @receiver f
 * @param fileName
 */
func (f *FileCommonFunc) SetFileName(fileName string) {
   f.fileName = fileName
}

/**
 * @Author: Jason Pang
 * @Description: 文件类
 */
type FileNode struct {
   FileCommonFunc
}

/**
 * @Author: Jason Pang
 * @Description: 文件类显示文件内容
 * @receiver f
 */
func (f *FileNode) Display(separator string) {
   fmt.Println(separator + f.fileName + "   文件内容为:Hello,world")
}

/**
 * @Author: Jason Pang
 * @Description: 目录类
 */
type DirectoryNode struct {
   FileCommonFunc
   nodes []FileSystemNode
}

/**
 * @Author: Jason Pang
 * @Description: 目录类展示文件名
 * @receiver d
 */
func (d *DirectoryNode) Display(separator string) {
   fmt.Println(separator + d.fileName)
   for _, node := range d.nodes {
      node.Display(separator + Separator)
   }
}

/**
 * @Author: Jason Pang
 * @Description: 添加目录或者文件
 * @receiver d
 * @param f
 */
func (d *DirectoryNode) Add(f FileSystemNode) {
   d.nodes = append(d.nodes, f)
}
func main() {
   //初始化
   biji := DirectoryNode{}
   biji.SetFileName("笔记")

   huiyi := DirectoryNode{}
   huiyi.SetFileName("会议")

   chenhui := FileNode{}
   chenhui.SetFileName("晨会.md")

   zhouhui := FileNode{}
   zhouhui.SetFileName("周会.md")
   //组装
   biji.Add(&huiyi)
   huiyi.Add(&chenhui)
   huiyi.Add(&zhouhui)
   //显示
   biji.Display(Separator)
}

显示:

➜ myproject go run main.go

–笔记

----会议

------晨会.md 文件内容为:Hello,world

------周会.md 文件内容为:Hello,world

文件类和目录类都实现了FileSystemNode接口,所以目录类管理文件类如同管理自己一样。两者都组合了FileCommonFunc类,可以复用相同功能。最后就是两者可以独立变化,如目录类有Add功能,但文件类没有。

3.总结

组合模式是对指定场景有用,所以大家能不能用到,完全看运气。这个设计模式满足单一职责原则、开闭原则、里氏替换原则。

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

往期文章回顾:

招聘

  1. 字节跳动|内推大放送
  2. 字节跳动|今日头条广州服务端研发工程师内推
  3. 字节跳动|抖音电商急招上海前端开发工程
  4. 字节跳动|抖音电商上海资深服务端开发工程师-交易
  5. 字节跳动|抖音电商武汉服务端(高级)开发工程师
  6. 字节跳动|飞书大客户产品经理内推咯
  7. 字节跳动|抖音电商服务端技术岗位虚位以待
  8. 字节跳动招聘专题

设计模式

  1. Go设计模式(15)-门面模式
  2. Go设计模式(14)-适配器模式
  3. Go设计模式(13)-装饰器模式
  4. Go设计模式(12)-桥接模式
  5. Go设计模式(11)-代理模式
  6. Go设计模式(10)-原型模式
  7. Go设计模式(9)-建造者模式
  8. Go设计模式(8)-抽象工厂
  9. Go设计模式(7)-工厂模式
  10. Go设计模式(6)-单例模式
  11. Go设计模式(5)-类图符号表示法
  12. Go设计模式(4)-代码编写优化
  13. Go设计模式(4)-代码编写
  14. Go设计模式(3)-设计原则
  15. Go设计模式(2)-面向对象分析与设计
  16. Go设计模式(1)-语法

语言

  1. 再也不怕获取不到Gin请求数据了
  2. 一文搞懂pprof
  3. Go工具之generate
  4. Go单例实现方案
  5. Go通道实现原理
  6. Go定时器实现原理
  7. Beego框架使用
  8. Golang源码BUG追查
  9. Gin框架简洁版
  10. Gin源码剖析

架构

  1. 分页复选设计的坑
  2. 支付接入常规问题
  3. 限流实现2
  4. 秒杀系统
  5. 分布式系统与一致性协议
  6. 微服务之服务框架和注册中心
  7. 浅谈微服务
  8. 限流实现1
  9. CDN请求过程详解
  10. 常用缓存技巧
  11. 如何高效对接第三方支付
  12. 算法总结

存储

  1. MySQL开发规范
  2. Redis实现分布式锁
  3. 事务原子性、一致性、持久性的实现原理
  4. InnoDB锁与事务简析

网络

  1. HTTP2.0基础教程
  2. HTTPS配置实战
  3. HTTPS连接过程
  4. TCP性能优化

工具

  1. GoLand实用技巧
  2. 根据mysql表自动生成go struct
  3. Markdown编辑器推荐-typora

读书笔记

  1. 《毛选》推荐
  2. 原则
  3. 资治通鉴
  4. 敏捷革命
  5. 如何锻炼自己的记忆力
  6. 简单的逻辑学-读后感
  7. 热风-读后感
  8. 论语-读后感
  9. 孙子兵法-读后感

思考

  1. 对写博客的一些思考
  2. 晚上打119的经历
  3. 为动员一切力量争取胜利而斗争
  4. 反对自由主义
  5. 实践论
  6. 评价自己的标准
  7. 2020博客总结
  8. 服务端团队假期值班方案
  9. 项目流程管理
  10. 对项目管理的一些看法
  11. 对产品经理的一些思考
  12. 关于程序员职业发展的思考
  13. 关于代码review的思考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值