Go语言设计模式汇总
Go语言从面世就受到了业界的普遍关注,随着区块链的火热Go语言的地位也急速蹿升,为了让读者对设计模式在Go语言中有一个初步的了解和概念,本偏对Go语言中的设计模式进行了整合和归纳,希望能对大家的学习起到一定的帮助。
设计模式背景和起源
在介绍设计模式的起源之前,我们先要了解一下模式的诞生与发展。与很多软件工程技术一样,模式起源于建筑领域,毕竟与只有几十年历史的软件工程相比,已经拥有几千年沉淀的建筑工程有太多值得学习和借鉴的地方。
每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的成功的解决方案,无须再重复相同的工作。这个定义可以简单地用一句话表示:
模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。
设计模式是什么
俗话说:站在别人的肩膀上,我们会看得更远。设计模式的出现可以让我们站在前人的肩膀上,通过一些成熟的设计方案来指导新项目的开发和设计,以便于我们开发出具有更好的灵活性和可扩展性,也更易于复用的软件系统。
设计模式的一般定义如下:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。
狭义的设计模式是指GoF在《设计模式:可复用面向对象软件的基础》一书中所介绍的23种经典设计模式,不过设计模式并不仅仅只有这23种,随着软件开发技术的发展,越来越多的新模式不断诞生并得以应用。
设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素,其中关键要素是模式名称、问题、解决方案和效果。
模式名称(Pattern Name)通过一两个词来描述模式的问题、解决方案和效果,以便更好地理解模式并方便开发人员之间的交流,绝大多数模式都是根据其功能或模式结构来命名的;
问题(Problem)描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因;
解决方案(Solution)描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过UML类图和核心代码来进行描述;
效果(Consequences)描述了模式的优缺点以及在使用模式时应权衡的问题。
Go语言模式分类
在分类之前,我们需要明白模式的大体分类,以及他们都分别代表什么意思:
创建模式:对类的实例化过程的抽象。一些系统在创建对象时,需要动态地决定怎样创建对象,创建哪些对象,以及如何组合和表示这些对象。创建模式描述了怎样构造和封装这些动态的决定。包含类的创建模式和对象的创建模式。
结构模式:描述如何将类或对象结合在一起形成更大的结构。分为类的结构模式和对象的结构模式。类的结构模式使用继承把类,接口等组合在一起,以形成更大的结构。类的结构模式是静态的。对象的结构模式描述怎样把各种不同类型的对象组合在一起,以实现新的功能的方法。对象的结构模式是动态的。
行为模式:对在不同的对象之间划分责任和算法的抽象化。不仅仅是关于类和对象的,并是关于他们之间的相互作用。类的行为模式使用继承关系在几个类之间分配行为。对象的行为模式则使用对象的聚合来分配行为。
模式分类表:
所属类型 | 模式名称 | 模式 | 简单定义 |
---|---|---|---|
创建模式 | Abstract Factory | 抽象工厂 | 提供用于创建相关对象系列的接口 |
Builder | 生成器 | 使用简单对象构建复杂对象 | |
Factory Method | 工厂方法 | 将对象的实例化延迟到用于创建实例的专用函数 | |
row 2 col 2 | 对象池 | 实例化并维护一组相同类型的对象实例 | |
Singleton | 单例 | 将类型的实例化限制为一个对象 | |
结构模式 | Adapter | 适配器 | 适配另一个不兼容的接口来一起工作 |
Bridge | 桥接 | 将接口与其实现分离,以便两者可以独立变化 | |
Composite | 组合 | 封装并提供对许多不同对象的访问 | |
Decorator | 装饰 | 静态或动态地向对象添加行为 | |
Facade | 外观 | 使用一种类型作为许多其他类型的API | |
Flyweight | 享元 | 运用共享技术有效地支持大量细粒度的对象 | |
Proxy | 代理 | 为对象提供代理以控制其操作 | |
行为模式 | Chain of Responsibility | 职责链 | 避免通过提供超过对象处理请求的机会来将发送方与接收方耦合 |
Command | 命令 | 捆绑命令和参数以便稍后调用 | |
Mediator | 中介者 | 连接对象并充当代理 | |
Memento | 备忘录 | 生成可用于返回先前状态的不透明令牌 | |
Observer | 观察者 | 提供回调以通知事件/数据更改 | |
Registry | 注册 | 跟踪给定类的所有子类 | |
State | 状态 | 根据内部状态封装同一对象的不同行为 | |
Strategy | 策略 | 允许在运行时选择算法的行为 | |
Template | 模板 | 定义一个将某些方法推迟到子类的框架类 | |
Visitor | 访问者 | 将算法与其运行的对象分开 | |
同步模式 | Condition Variable | 条件变量 | 为线程提供一种机制,以暂时放弃访问以等待某些条件 |
Lock/Mutex | 锁定/互斥 | 对资源实施互斥限制以获得独占访问权限 | |
Monitor | 监视器 | 互斥和条件变量模式的组合 | |
Read-Write Lock | 读写锁定 | 允许并行读取访问,但仅对资源的写入操作进行独占访问 | |
Semaphore | 信号 | 允许控制对公共资源的访问 | |
并行模式 | N-Barrier | N-二道闸 | 阻止进程继续进行,直到所有N个进程都到达屏障 |
Bounded Parallelism | 有界并行 | 完成大量资源限制的独立任务 | |
Broadcast | 广播 | 把一个消息同时传输到所有接收端 | |
Coroutines | 协同程序 | 允许在特定地方暂停和继续执行的子程序 | |
Generators | 生成器 | 一次性生成一系列值 | |
Reactor | 反应 | 服务处理程序使用I/O多路复用策略来同步、有序的处理一个或多个客户端并发请求 | |
Parallelism | 并行 | 完成大量独立任务 | |
Producer Consumer | 生产者消费者 | 从任务执行中分离任务 | |
Scheduler | 调度器 | 协调任务步骤 | |
消息传递模式 | Fan-In | 扇入 | 该模块直接调用上级模块的个数,像漏斗型一样去工作 |
Fan-Out | 扇出 | 该模块直接调用的下级模块的个数 | |
Futures & Promises | Futures & Promises | 扮演一个占位角色,对未知的结果用于同步 | |
Publish/Subscribe | Publish/Subscribe | 将信息传递给订阅者 | |
Push & Pull | Push & Pull | 把一个管道上的消息分发给多人 | |
稳定模式 | Bulkheads | Bulkheads | 实施故障遏制原则(即防止级联故障) |
Circuit-Breaker | 断路器 | 当请求有可能失败时,停止流动的请求 | |
Deadline | 截止日期 | 一旦响应变缓,允许客户端停止一个正在等待的响应 | |
Fail-Fast机制 | 快速失败 | 检查请求开始时所需资源的可用性,如果不满足要求则失败 | |
Handshaking | 握手 | 询问组件是否可以承受更多负载,如果不能,则请求被拒绝 | |
Steady-State | 稳定状态 | 为每一个服务积累一个资源,其它服务必须回收这些资源 | |
剖析模式 | Timing Functions | 时序功能 | 包装函数并记录执行 |
成例 | Functional Options | 功能选项 | 允许给默认值创建clean API和惯用重载 |
反模式 | 级联故障 | 级联故障 | 互连部件系统中的故障,其中部件的故障导致多米诺骨牌效应 |
个人观点
作为设计模式的忠实粉丝和推广人员,在正式学习设计模式之前,我结合多年的工作经验和学习心得,这里给出了下列个人的建议:
-
掌握设计模式并不是件很难的事情,关键在于多思考,多实践,不要听到人家说懂几个设计模式就很“牛”,只要用心学习,设计模式也就那么回事,你也可以很“牛”的,一定要有信心。
-
在学习每一个设计模式时至少应该掌握如下几点:这个设计模式的意图是什么,它要解决一个什么问题,什么时候可以使用它;它是如何解决的,掌握它的结构图,记住它的关键代码;能够想到至少两个它的应用实例,一个生活中的,一个软件中的;这个模式的优缺点是什么,在使用时要注意什么。当你能够回答上述所有问题时,恭喜你,你了解一个设计模式了,至于掌握它,用多了自然就掌握了。
-
“如果想体验一下运用模式的感觉,那么最好的方法就是运用它们”。正如很多书里所说的,无论学习什么都要做到知行合一。
-
千万不要滥用模式,不要试图在一个系统中用上所有的模式。每个模式都有自己的适用场景,不能为了使用模式而使用模式,滥用模式不如不用模式,因为滥用的结果得不到“艺术品”一样的软件,很有可能是一堆垃圾代码。
-
如果将设计模式比喻成“三十六计”,那么每一个模式都是一种计策,它为解决某一类问题而诞生,不管这个设计模式的难度如何,使用频率高不高,我建议大家都应该好好学学,多学一个模式也就意味着你多了“一计”,说不定什么时候一不小心就用上了,
-
设计模式的“上乘”境界:“手中无模式,心中有模式”。模式使用的最高境界是你已经不知道具体某个设计模式的定义和结构了,但你会灵活自如地选择一种设计方案【其实就是某个设计模式】来解决某个问题,设计模式已经成为你开发技能的一部分,能够手到擒来,“内功”与“招式”已浑然一体,要达到这个境界并不是看完某本书或者开发一两个项目就能够实现的,它需要不断沉淀与积累,所以,对模式的学习不要急于求成。
随着笔者的不断学习和深入,在后面也会带领大家逐个去深入学习设计模式的意义和使用,喜欢的小伙伴可以点点关注,我会定期更新Go的设计模式的学习贴,最后谢谢大家的支持。
Go语言从面世就受到了业界的普遍关注,随着区块链的火热Go语言的地位也急速蹿升,为了让读者对设计模式在Go语言中有一个初步的了解和概念,本偏对Go语言中的设计模式进行了整合和归纳,希望能对大家的学习起到一定的帮助。
设计模式背景和起源
在介绍设计模式的起源之前,我们先要了解一下模式的诞生与发展。与很多软件工程技术一样,模式起源于建筑领域,毕竟与只有几十年历史的软件工程相比,已经拥有几千年沉淀的建筑工程有太多值得学习和借鉴的地方。
每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的成功的解决方案,无须再重复相同的工作。这个定义可以简单地用一句话表示:
模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。
设计模式是什么
俗话说:站在别人的肩膀上,我们会看得更远。设计模式的出现可以让我们站在前人的肩膀上,通过一些成熟的设计方案来指导新项目的开发和设计,以便于我们开发出具有更好的灵活性和可扩展性,也更易于复用的软件系统。
设计模式的一般定义如下:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。
狭义的设计模式是指GoF在《设计模式:可复用面向对象软件的基础》一书中所介绍的23种经典设计模式,不过设计模式并不仅仅只有这23种,随着软件开发技术的发展,越来越多的新模式不断诞生并得以应用。
设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素,其中关键要素是模式名称、问题、解决方案和效果。
模式名称(Pattern Name)通过一两个词来描述模式的问题、解决方案和效果,以便更好地理解模式并方便开发人员之间的交流,绝大多数模式都是根据其功能或模式结构来命名的;
问题(Problem)描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因;
解决方案(Solution)描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过UML类图和核心代码来进行描述;
效果(Consequences)描述了模式的优缺点以及在使用模式时应权衡的问题。
Go语言模式分类
在分类之前,我们需要明白模式的大体分类,以及他们都分别代表什么意思:
创建模式:对类的实例化过程的抽象。一些系统在创建对象时,需要动态地决定怎样创建对象,创建哪些对象,以及如何组合和表示这些对象。创建模式描述了怎样构造和封装这些动态的决定。包含类的创建模式和对象的创建模式。
结构模式:描述如何将类或对象结合在一起形成更大的结构。分为类的结构模式和对象的结构模式。类的结构模式使用继承把类,接口等组合在一起,以形成更大的结构。类的结构模式是静态的。对象的结构模式描述怎样把各种不同类型的对象组合在一起,以实现新的功能的方法。对象的结构模式是动态的。
行为模式:对在不同的对象之间划分责任和算法的抽象化。不仅仅是关于类和对象的,并是关于他们之间的相互作用。类的行为模式使用继承关系在几个类之间分配行为。对象的行为模式则使用对象的聚合来分配行为。
模式分类表:
所属类型 | 模式名称 | 模式 | 简单定义 |
---|---|---|---|
创建模式 | Abstract Factory | 抽象工厂 | 提供用于创建相关对象系列的接口 |
Builder | 生成器 | 使用简单对象构建复杂对象 | |
Factory Method | 工厂方法 | 将对象的实例化延迟到用于创建实例的专用函数 | |
row 2 col 2 | 对象池 | 实例化并维护一组相同类型的对象实例 | |
Singleton | 单例 | 将类型的实例化限制为一个对象 | |
结构模式 | Adapter | 适配器 | 适配另一个不兼容的接口来一起工作 |
Bridge | 桥接 | 将接口与其实现分离,以便两者可以独立变化 | |
Composite | 组合 | 封装并提供对许多不同对象的访问 | |
Decorator | 装饰 | 静态或动态地向对象添加行为 | |
Facade | 外观 | 使用一种类型作为许多其他类型的API | |
Flyweight | 享元 | 运用共享技术有效地支持大量细粒度的对象 | |
Proxy | 代理 | 为对象提供代理以控制其操作 | |
行为模式 | Chain of Responsibility | 职责链 | 避免通过提供超过对象处理请求的机会来将发送方与接收方耦合 |
Command | 命令 | 捆绑命令和参数以便稍后调用 | |
Mediator | 中介者 | 连接对象并充当代理 | |
Memento | 备忘录 | 生成可用于返回先前状态的不透明令牌 | |
Observer | 观察者 | 提供回调以通知事件/数据更改 | |
Registry | 注册 | 跟踪给定类的所有子类 | |
State | 状态 | 根据内部状态封装同一对象的不同行为 | |
Strategy | 策略 | 允许在运行时选择算法的行为 | |
Template | 模板 | 定义一个将某些方法推迟到子类的框架类 | |
Visitor | 访问者 | 将算法与其运行的对象分开 | |
同步模式 | Condition Variable | 条件变量 | 为线程提供一种机制,以暂时放弃访问以等待某些条件 |
Lock/Mutex | 锁定/互斥 | 对资源实施互斥限制以获得独占访问权限 | |
Monitor | 监视器 | 互斥和条件变量模式的组合 | |
Read-Write Lock | 读写锁定 | 允许并行读取访问,但仅对资源的写入操作进行独占访问 | |
Semaphore | 信号 | 允许控制对公共资源的访问 | |
并行模式 | N-Barrier | N-二道闸 | 阻止进程继续进行,直到所有N个进程都到达屏障 |
Bounded Parallelism | 有界并行 | 完成大量资源限制的独立任务 | |
Broadcast | 广播 | 把一个消息同时传输到所有接收端 | |
Coroutines | 协同程序 | 允许在特定地方暂停和继续执行的子程序 | |
Generators | 生成器 | 一次性生成一系列值 | |
Reactor | 反应 | 服务处理程序使用I/O多路复用策略来同步、有序的处理一个或多个客户端并发请求 | |
Parallelism | 并行 | 完成大量独立任务 | |
Producer Consumer | 生产者消费者 | 从任务执行中分离任务 | |
Scheduler | 调度器 | 协调任务步骤 | |
消息传递模式 | Fan-In | 扇入 | 该模块直接调用上级模块的个数,像漏斗型一样去工作 |
Fan-Out | 扇出 | 该模块直接调用的下级模块的个数 | |
Futures & Promises | Futures & Promises | 扮演一个占位角色,对未知的结果用于同步 | |
Publish/Subscribe | Publish/Subscribe | 将信息传递给订阅者 | |
Push & Pull | Push & Pull | 把一个管道上的消息分发给多人 | |
稳定模式 | Bulkheads | Bulkheads | 实施故障遏制原则(即防止级联故障) |
Circuit-Breaker | 断路器 | 当请求有可能失败时,停止流动的请求 | |
Deadline | 截止日期 | 一旦响应变缓,允许客户端停止一个正在等待的响应 | |
Fail-Fast机制 | 快速失败 | 检查请求开始时所需资源的可用性,如果不满足要求则失败 | |
Handshaking | 握手 | 询问组件是否可以承受更多负载,如果不能,则请求被拒绝 | |
Steady-State | 稳定状态 | 为每一个服务积累一个资源,其它服务必须回收这些资源 | |
剖析模式 | Timing Functions | 时序功能 | 包装函数并记录执行 |
成例 | Functional Options | 功能选项 | 允许给默认值创建clean API和惯用重载 |
反模式 | 级联故障 | 级联故障 | 互连部件系统中的故障,其中部件的故障导致多米诺骨牌效应 |
个人观点
作为设计模式的忠实粉丝和推广人员,在正式学习设计模式之前,我结合多年的工作经验和学习心得,这里给出了下列个人的建议:
-
掌握设计模式并不是件很难的事情,关键在于多思考,多实践,不要听到人家说懂几个设计模式就很“牛”,只要用心学习,设计模式也就那么回事,你也可以很“牛”的,一定要有信心。
-
在学习每一个设计模式时至少应该掌握如下几点:这个设计模式的意图是什么,它要解决一个什么问题,什么时候可以使用它;它是如何解决的,掌握它的结构图,记住它的关键代码;能够想到至少两个它的应用实例,一个生活中的,一个软件中的;这个模式的优缺点是什么,在使用时要注意什么。当你能够回答上述所有问题时,恭喜你,你了解一个设计模式了,至于掌握它,用多了自然就掌握了。
-
“如果想体验一下运用模式的感觉,那么最好的方法就是运用它们”。正如很多书里所说的,无论学习什么都要做到知行合一。
-
千万不要滥用模式,不要试图在一个系统中用上所有的模式。每个模式都有自己的适用场景,不能为了使用模式而使用模式,滥用模式不如不用模式,因为滥用的结果得不到“艺术品”一样的软件,很有可能是一堆垃圾代码。
-
如果将设计模式比喻成“三十六计”,那么每一个模式都是一种计策,它为解决某一类问题而诞生,不管这个设计模式的难度如何,使用频率高不高,我建议大家都应该好好学学,多学一个模式也就意味着你多了“一计”,说不定什么时候一不小心就用上了,
-
设计模式的“上乘”境界:“手中无模式,心中有模式”。模式使用的最高境界是你已经不知道具体某个设计模式的定义和结构了,但你会灵活自如地选择一种设计方案【其实就是某个设计模式】来解决某个问题,设计模式已经成为你开发技能的一部分,能够手到擒来,“内功”与“招式”已浑然一体,要达到这个境界并不是看完某本书或者开发一两个项目就能够实现的,它需要不断沉淀与积累,所以,对模式的学习不要急于求成。
随着笔者的不断学习和深入,在后面也会带领大家逐个去深入学习设计模式的意义和使用,喜欢的小伙伴可以点点关注,我会定期更新Go的设计模式的学习贴,最后谢谢大家的支持。