设计模式,Let's “Go”! (上)

前言

最近读了《Head First 设计模式》,每天早上看一章,学习一个设计模式,做些笔记,然后晚上抽空用刚学习的 Go 语言实现一下。半个月下来书读完了,留下了一些笔记,写文章总结一下。

书中的例子都是 Java 写的,但几乎没使用 Java 语言的特性,很容易看懂。对于我来说,就是一个 PHP 开发工程师,读了一本 用 Java 语言实现设计模式的书,然后用 Go 写了一遍。。。=_=

本文为每个设计模式只分配了一小节,总结一下设计模式的概念和特点以及适用场景,并介绍了自己用代码实现时的列举的例子,用现实生活中的事物对比加深一下记忆 ( 代码实现中所有的例子都是自己原创的,有牵强的部分,不要介意)。每个模式篇幅不大,可以给新人入门,给了解过设计模式的人作为速查。

文章经常被人爬,而且还不注明原地址,我在这里的更新和纠错没法同步,这里注明一下原文地址:https://cloud.tencent.com/developer/user/1148723/activities 以防误人子弟。

放上 Go 实现设计模式的 源码地址:DesignPattern-枕边书-Github ,偶有更新,欢迎 star。OK,正文开始。

策略模式(Strategy)

介绍

策略模式: 将算法或操作抽象成实现共同接口、可以被替换的类,实现逻辑和具体算法的解耦。

  • 将各种行为抽象成算法,封装算法为对象;
  • 算法实现共同接口,调用者调用时不考虑算法具体实现,调用接口方法即可;
  • 调用者可随时替换此算法对象;

场景

  • 多个方法择一使用,且他们会被随时替换;
  • 方法没有共性,使用继承会有大量重写,使用接口会有大量重复使用;

实现

  1. 两个算法: 冒泡排序和快速排序;
  2. 抽象冒泡排序和快速排序为算法对象,实现算法接口,拥有 used() 被使用方法;
  3. 计算器计算时不用理会是什么算法,调用 used() 即可;

观察者模式(Observer)

介绍

观察者模式:主题主动向观察者推送变化,解决观察者对主题对象的依赖。

  • 观察者实现被通知接口,并在主题上注册,主题只保存观察者的引用,不关心观察者的实现;
  • 在主题有变化时调用观察者的通知接口来通知已注册的观察者;
  • 通知方式有(主题变化时将变化数据推送给观察者)和(主题只告知变化,观察者主动来拉取数据);

场景

  • 一个主题,多个观察者,主题的任何变动,观察者都要第一时刻得到;
  • 观察者获取主题变化困难,定时不及时,轮询消耗大;
  • 观察者可以随时停止关注某主题;

实现

  1. 张三和李四是记者,他们需要及时了解城市发生的新闻;
  2. 张三和李四在电视台注册了自己的信息;
  3. 城市发生了新闻,电视台遍历注册信息,通知了张三和李四;
  4. 李四退休了,在电视台注销了自己的信息;
  5. 城市又发生了新闻,电视台只通知了张三;

装饰者模式(Decorator)

介绍

装饰者模式:包装一个对象,在被装饰对象的基础上添加功能

  • 装饰者与被装饰对象拥有同一个超类,装饰者拥有被装饰对象的所有外部接口,可被调用,外界无法感知调用的是装饰者还是被装饰者;
  • 装饰者需要被装饰者作为参数传入,并在装饰者内部,在被装饰者实现的基础上添加或修改某些功能后,提供同被装饰者一样的接口;
  • 装饰者也可被另一个装饰者装饰,即嵌套装饰;
  • 装饰者是一群包装类,由于装饰的复杂性,会多出很多个装饰者小类;

场景

  • 对象需要动态地添加和修改功能;
  • 功能改变后不影响原对象的使用;

实现

  1. 在商店内,花作为被装饰者对象、红丝带和盒子作为花的装饰者;
  2. 花、红丝带、盒子有共同的超类“商品”,他们都能被卖掉;
  3. 我们可以在红丝带装饰过花后,再用盒子再包装一次;
  4. 包装后的花,顾客买时也不会受到任何影响;

工厂模式(Factory)

介绍

工厂模式: 顾名思义,工厂模式是对象的生产器,解耦用户对具体对象的依赖。

  • 实现依赖倒置,让用户通过一个产品工厂依赖产品的抽象,而不是一个具体的产品;
  • 简单工厂模式:接收参数并根据参数创建对应类,将对象的实例化和具体使用解耦;
  • 抽象工厂模式:将工厂抽象出多个生产接口,不同类型的工厂调用生产接口时,生产不同类型的对象;
  • 简单工厂常配合抽象工厂一起使用;

场景

  • 根据不同条件需求不同的对象;
  • 对象实例化的代码经常需要修改;

实现

  1. 简单工厂:向鞋厂内传入不同的类型(布制),鞋厂会生产出不同类型的鞋子(布鞋);
  2. 抽象工厂:有两座鞋厂:李宁鞋厂、Adidas鞋厂,他们能生产对应各自品牌的鞋子;
  3. 搭配使用:向不同的抽象工厂(李宁)传入不同的类型(运动类型),会生产出对应品牌对应类型的鞋子(李宁运动鞋);

单例模式(Singleton)

介绍

单例模式:保证同一个类全局只有一个实例对象;

  • 在第一次实例化后会使用静态变量保存实例,后续全局使用此静态变量;
  • 一般将构造方法私有化,构造方法添加 final 关键字无法被重写,添加一个类静态方法用于返回此实例;
  • 在多线程时应该考虑并发问题,防止两次调用都被判定为实例未初始化而重复初始化对象;

场景

  • 全局共享同一个实例对象(数据库连接等);
  • 某一处对此对象的更新全局可见;

实现

  1. 利用 Go 中包的可见性规则来隐藏对象的实例化权限;
  2. 使用包变量保存实例对象,获取实例时判断是否已实例化,如为nil,实例化对象并返回,如有值,直接返回值;
  3. 待用锁实现 Go routine 并发时的问题;

命令模式(Command)

介绍

命令模式:将一个命令封装成对象,解耦命令的发起者和执行者。

  • 命令对象实现命令接口(excute[、undo]),命令发起者实例化命令对象,并传递此对象,并不关心此对象由谁执行;
  • 命令执行者只负责调用命令对象的执行方法即可,不关心对象是由谁生成的;
  • 与策略模式不同之处:策略模式是通过不同的算法做同一件事情(例如排序),而命令模式则是通过不同的命令做不同的事情;

场景

  • 命令发起者与执行者无法直接接触;
  • 命令需要撤销功能,却不易保存命令执行状态信息时;

实现

  1. 指挥官创建了一个“从树下跑到草地上”的命令;
  2. 命令被分配给张三执行,张三作为军人,接到命令后不管命令的具体内容,而是直接调用命令的执行接口执行;
  3. 指挥官发布了撤销指令,张三又从草地上跑到了树下;

适配器模式(Adapter)

介绍

适配器模式:包装对象提供一个接口,以适配调用者

  • 适配器通过一个中间对象,封装目标接口适应调用者调用;
  • 调用者调用此适配器,以达到调用目标接口的目的;
  • 适配器模式与装饰者模式的不同之处:适配器模式不改变接口的功能,而装饰者会添加或修改原接口功能;

场景

  • 提供的接口与调用者调用的其他的接口都不一致;
  • 为一个特殊接口修改调用者的调用方式得不偿失;

实现

  1. 张三是个正常人,他能通过说话直接地表达自己;
  2. 李四是个聋哑人,他没法直接表达自己,但他会写字;
  3. 笔记本作为一个适配器,用笔记本“包装”了李四之后,当李四需要表达自己想法时,调用笔记本的“表达”功能,笔记本再调用李四“写字”的方法;

外观模式(Facade)

介绍

外观模式:通过封装多个复杂的接口来提供一个简化接口来实现一个复杂功能。

  • 外观模式是通过封装多个接口来将接口简单化
  • 外观模式不会改变原有的多个复杂的单一接口,这些接口依然能被单独调用,只是提供了一个额外的接口;
  • 外观模式与适配器模式的不同之处:外观模式是整合多个接口并添加一个简化接口,适配器是适配一个接口;

场景

  • 实现某一功能需要调用多个复杂接口;
  • 经常需要实现此功能;

实现

  1. 正常的冲咖啡步骤是:磨咖啡豆、烧开水、倒开水搅拌咖啡。
  2. 我们经常需要直接冲咖啡,而不是使用单一步骤,每次喝咖啡时调用三个方法很麻烦;
  3. 封装三个接口,额外提供一个 “冲咖啡” 的方法,需要喝咖啡时只需要调用一次冲咖啡方法即可;

小结

《Head First 设计模式》这书真心不错,例子很轻松,给人很多时间和空间来思考,同时介绍模式时使用结合故事,层层深入的方法,让人印象很深刻,推荐。

书中详细介绍了 14 个基础设计模式,还有 9 个简化版,就自己查资料结合自己的理解来总结了。

本系统准备写三篇,敬请期待中下篇。

关于本文有什么问题可以在下面留言交流,如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。一直在更新,欢迎 关注

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C/C++基础

C++以智能指针管理内存资源

C++作为一门应用广泛的高级编程语言,却没有像Java、C#等语言拥有垃圾回收(Garbage Collection )机制来自动进行内存管理,这也是C++一直...

523
来自专栏IT笔记

JAVA工作三年面试(二)

这里讲述下第二家公司的面试,这是一家大型互联网公司,简称W,一般像博主这样的传统行业去跳到这种公司简直是要跪舔的节奏,所以从一开始就带着一份敬仰之情去面试。由于...

3557
来自专栏好好学java的技术栈

一文看透java8新特性

毫无疑问,Java 8发行版是自Java 5(发行于2004,已经过了相当一段时间了)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发工具...

662
来自专栏大闲人柴毛毛

柴毛毛大话设计模式——开发常用的设计模式梳理

写在最前 本文是笔者的一点经验总结,主要介绍几种在Web开发中使用频率较高的设计模式。 本文篇幅较长,建议各位同学挑选感兴趣的设计模式阅读。 在阅读的同时,也...

4287
来自专栏PhpZendo

PHP 多任务协程处理

上周 有幸和同事一起在 SilverStripe 分享最近的工作事宜。今天我计划分享 PHP 异步编程,不过由于上周我聊过 ReactPHP;我决定讨论一些不一...

311
来自专栏iKcamp

翻译连载 | 第 10 章:异步的函数式(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇

原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 第 10 章:异步的函数式(下)...

1795
来自专栏何俊林

Android应用内存泄露分析以及优化方案

【小提醒】阅读本文约耗时10分钟左右。 前言:今天看了微信的价值理念,我觉得和我的想法很像,像张小龙说的提供一供干净的阅读空间,不过多的干预用户的工作,不通过粘...

2119
来自专栏逸鹏说道

必备 .NET - C# 异常处理

欢迎查看首个“必备.NET”专栏。您可以在其中了解 Microsoft .NET Framework 领域的所有最新动态,无论是 C# vNext 的最新进展(...

2606
来自专栏腾讯Bugly的专栏

那些年,我们一起写过的“单例模式”

本文来自:“天天P图攻城狮”公众号(ttpic_dev) 题记 度娘上对设计模式(Design pattern)的定义是:“一套被反复使用、多数人知晓的、经过分...

3874
来自专栏美团技术团队

Node.js Stream - 基础篇

背景 在构建较复杂的系统时,通常将其拆解为功能独立的若干部分。这些部分的接口遵循一定的规范,通过某种方式相连,以共同完成较复杂的任务。譬如,shell通过管道|...

3605

扫码关注云+社区