* { color: #3e3e3e }
body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif; font-size: 15px }
p { line-height: 25.6px; text-align: justify; margin: 23.7px 0 }
blockquote { border-left: 2px solid rgba(128,128,128,0.075); background-color: rgba(128,128,128,0.05); padding: 10px -1px; margin: 0px }
blockquote p { color: #898989; margin: 0px }
strong { font-weight: 700; color: #3e3e3e }
pre { background-color: #f8f8f8; overflow: scroll; padding: 12px 13px; font-size: 13px; color: #898989 }
h1,h2,h3,h4,h5,h6 { text-align: left; font-weight: bold }
hr { border: 1px solid #ddd }
h1 { font-size: 170% }
h1:first-child { margin-top: 0; padding-top: .25em; border-top: none }
table { padding: 0; border-collapse: collapse }
table tr { border-top: 1px solid #cccccc; background-color: white; margin: 0; padding: 0 }
table tr:nth-child(2n) { background-color: #f8f8f8 }
table tr th { font-weight: bold; border: 1px solid #cccccc; margin: 0; padding: 6px 13px }
table tr td { border: 1px solid #cccccc; margin: 0; padding: 6px 13px }
table tr th :first-child,table tr td :first-child { margin-top: 0 }
table tr th :last-child,table tr td :last-child { margin-bottom: 0 }
a { color: #4183C4; text-decoration: none }
ul,ol { padding-left: 30px }
li { line-height: 24px }
hr { height: 2px; padding: 0; margin: 16px 0; background-color: #e7e7e7; border: 0 none; overflow: hidden; border-bottom: 1px solid #ddd }
pre { background: #f2f2f2; padding: 12px 13px }
code { padding: 2px 4px; color: #c7254e; background: #f9f2f4 }
code[class*="language-"],pre[class*="language-"] { color: black; background: none; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre; word-spacing: normal; line-height: 1.5 }
pre[class*="language-"] { position: relative; margin: .5em 0; border-left: 10px solid #358ccb; background-color: #fdfdfd; background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); overflow: visible; padding: 0 }
code[class*="language"] { max-height: inherit; height: 100%; padding: 0 1em; display: block; overflow: auto }
:not(pre)>code[class*="language-"],pre[class*="language-"] { background-color: #fdfdfd; margin-bottom: 1em }
:not(pre)>code[class*="language-"] { position: relative; padding: .2em; color: #c92c2c; border: 1px solid rgba(0, 0, 0, 0.1); display: inline; white-space: normal }
pre[class*="language-"]::before,pre[class*="language-"]::after { content: ""; z-index: -2; display: block; position: absolute; bottom: 0.75em; left: 0.18em; width: 40%; height: 20%; max-height: 13em }
:not(pre)>code[class*="language-"]::after,pre[class*="language-"]::after { right: 0.75em; left: auto }
.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata { color: #7D8B99 }
.token.punctuation { color: #5F6364 }
.token.property,.token.tag,.token.boolean,.token.number,.token.function-name,.token.constant,.token.symbol,.token.deleted { color: #c92c2c }
.token.selector,.token.attr-name,.token.string,.token.char,.token.function,.token.builtin,.token.inserted { color: #2f9c0a }
.token.operator,.token.entity,.token.url,.token.variable { color: #a67f59; background: rgba(255, 255, 255, 0.5) }
.token.atrule,.token.attr-value,.token.keyword,.token.class-name { color: #1990b8 }
.token.regex,.token.important { color: #e90 }
.language-css .token.string,.style .token.string { color: #a67f59; background: rgba(255, 255, 255, 0.5) }
.token.important { font-weight: normal }
.token.bold { font-weight: bold }
.token.italic { font-style: italic }
.token.entity { cursor: help }
.namespace { opacity: .7 }
.token.tab:not(:empty)::before,.token.cr::before,.token.lf::before { color: #e0d7d1 }
pre[class*="language-"].line-numbers { padding-left: 0 }
pre[class*="language-"].line-numbers code { padding-left: 3.8em }
pre[class*="language-"].line-numbers .line-numbers-rows { left: 0 }
pre[class*="language-"][data-line] { padding-top: 0; padding-bottom: 0; padding-left: 0 }
pre[data-line] code { position: relative; padding-left: 4em }
pre .line-highlight { margin-top: 0 }
pre.line-numbers { position: relative; padding-left: 3.8em; counter-reset: linenumber }
pre.line-numbers>code { position: relative }
.line-numbers .line-numbers-rows { position: absolute; top: 0; font-size: 100%; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid #999 }
.line-numbers-rows>span { display: block; counter-increment: linenumber }
.line-numbers-rows>span::before { content: counter(linenumber); color: #999; display: block; padding-right: 0.8em; text-align: right }

前言

接上篇 设计模式,Let's “Go”! (上), 继续更新设计模式,今天介绍的设计模式有模板模式、迭代器模式、组合模式、状态模式、代理模式、桥接模式和建造者模式;

文章对设计模式的特点和使用场景进行了总结,每个设计模式分配的篇幅较少,给了解过设计模式的作为速查,帮不了解设计模式的入门, 当然具体实现才是重点,使用现实生活中的事物例子来帮助理解设计模式。

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

文章经常被人爬,而且还不注明原地址,我在这里的更新和纠错没法同步,这里注明一下原文地址:http://www.cnblogs.com/zhenbianshu/p/7449868.html 以防误人子弟。


模板模式(Template)

介绍

模板模式:模板模式在抽象类或父类中抽象出算法步骤作为模板,模板的具体细节推迟到子类实现。

  • 模板模式在父类或抽象类中定义一个算法的骨架,并在父类或抽象类中实现共同的部分,各个不同的步骤由不同的子类分别实现;
  • 模板板式在父类的算法步骤中定义勾子(hook),在子类中判断并定义一些不是非通用步骤;
  • 模板模式与策略模式的不同之处在于,策略模式是针对多个不同的算法,而模板模式是针对一个算法的不同步骤,在模板模式中,只有一个算法;

场景

  • 多个算法有多个共同之处,但某些步骤略微不同;
  • 各子类步骤顺序一致,但步骤的具体实现有所不同时;

实现

  1. 有发邮件和发短信两种通讯方式;
  2. 他们都需要获取目标信息、格式化正文、填写发送方信息,但实现不同;
  3. 在信息类中抽象出三个步骤,具体的处理方式由两种通讯方式各自实现;
  4. 发送信息时调用信息类中的发送方法,发送方法会按照顺序自动调用对应的步骤;

迭代器模式(Iterator)

介绍

迭代器模式:迭代器模式允许调用者在不知道类内部实现的情况下遍历类元素

  • 迭代器接口常用方法有 length(),next(),previous(),remove()等;
  • 各类在内部实现迭代器接口,用对应的方法操作元素;
  • 调用者不考虑类内部实现,调用迭代器接口即可;

场景

  • 类使用不同的数据结构存储数据;
  • 需要对不同的数据类型进行遍历等操作;

实现

  1. 使用 slice 存储一列战马,使用 map 存储一列士兵;
  2. 战马和士兵结构都实现了迭代器接口;
  3. 获取战马数和士兵数,遍历战马和士兵,调用迭代器接口即可;

组合模式(Composite)

介绍

组合器模式:使用一种组件抽象来同时表达集合与元素,使用统一的接口来管理集合和元素。

  • 组合模式通常为树结构,父结点和子节点具有同样的抽象和接口;
  • 在操作集合时,会同时操作集合所属的具体元素
  • 通常给组合模式添加一个迭代器来完成组合结构的迭代;

场景

  • 管理的多个对象构成树型层级结构;
  • 操作高层级的对象时,需要同时其所属的下级对象,如界面窗口等;

实现

  1. 将军、队长、士兵构成树型层级结构,且他们都是战士,拥有战斗方法;
  2. 每位战士都保存着自己的下级名单,没有下级时忽略;
  3. 每个人在战斗时,都会率领着下级战斗;

状态模式(State)

介绍

状态模式:状态模式抽象出一个事物的状态作为类,解耦事物和不同状态下的行为;

  • 状态模式通过替换状态对象作为状态转换的方式;
  • 状态对象实现根据状态动作的接口,可以根据不同的动作做出对应的反应;
  • 状态模式与策略模式的实现相似,但状态模式是对类内部状态作出改变,而策略模式是针对算法封装;

场景

  • 事物有多种状态,且可以相互转换;
  • 事物多种状态下对同一动作做出的行为不同;

实现

  1. 植物有 幼苗、开花和成熟 三种状态,且它们会通过浇水和收获的动作进行相互转换;
  2. 幼苗和开花时不能收获,只能浇水,成熟状态只能收获,不需要再浇水;
  3. 定义三种状态,和它们对不同动作时的行为,植物通过三种对象的替换来进行状态转换;

代理模式(Proxy)

介绍

代理模式:给对象提供一个代理,由代理对象控制对原对象的调用;

  • 代理模式为一个对象(通常是大对象或无法复制的对象)创建另外一个类作为其访问的接口,所有对真实对象的请求都通过代理对象完成;
  • 代理对象可以控制用户对真实对象的访问权限,也可以在访问真实对象时附加功能;
  • 代理模式可被用作:远程代理,虚拟代理,安全代理,指针引用,延迟加载;

场景

  • 对象无法被直接访问时;
  • 对象过大,初始化较慢;
  • 对象不必要立刻初始化,可使用默认值代替;

实现

  1. 小明给暗恋对象写了一封信,在等回信;
  2. 邮递员是个非常忙的人,来不及去收取回信;
  3. 小明好声好气向邮递员要回信时,邮递员都推拖说自己要去取;
  4. 小明发怒了,邮递员终于抽时间去取了信给小明;
  5. 此信中邮递员就是代理模式中的代理,他实现了懒加载。
  6. 回信内容见源码:)

桥接模式(Bridge)

介绍

桥接模式:将事务的多个维度都抽象出来以解耦抽象与实际之间的绑定关系,使抽象和实际向着不同维度改变;

  • 桥接模式通过对象的组合来解决事物的多维度变化问题,以替代多继承的不灵活;
  • 桥接模式可以轻易在多维度上拓展,而不改变原有模式;
  • 桥接模式与策略模式的不同之处:策略模式是针对一个不变的主题替换抽象算法,而桥接模式是策略模式的高维度状态,它的主题也可能会被替换;

场景

  • 某事物在多个维度上都有变化;
  • 无法使用多继承或使用多继承会很不灵活;

实现

  1. 作画时可以使用铅笔和圆珠笔等不同的笔,也可以在宣纸或普通A4纸;
  2. 抽象出笔和纸两种对象;
  3. 自由组合笔和纸进行作画;

建造者模式(Builder)

介绍

建造者模式:建造者模式分离创建复杂对象的过程和细节,使得同样的创建过程能创建不同的对象。

  • 建造者模式将创建对象部件的一般过程抽象出接口,而由不同的建造者类实现具体的接口,实现过程的步骤;
  • 通过建造者,调用者不用考虑对象创建过程的细节,且建造者也可以被灵活替换;
  • 与模板模式的区别:建造者模式使用类的组合进行对象的创建,而模板模式使用类的继承实现对象的具体构造;
  • 与工厂模式的区别:工厂模式会返回一个具体类,而建造者模式会建造出一个由多个类组装而成的完整类;

场景

  • 对象的创建包含其他对象为类元素,创建过程复杂;
  • 多个复杂对象的创建过程具有高度相似性;

实现

  1. 中国式建筑有金色屋顶和红色大门,而意式建筑有圆项和白色大门;
  2. 中国建筑师和意式建筑师分别擅长建造不同类型的建筑;
  3. 我们在盖不同类型的房子时先创建一个建筑师,再用建筑师去创建对应风格的房子;

小结

开发者对设计模式常陷入两个误区,要么极度推崇,要么弃如弊履。 极度推崇的人认为设计模式就是圣经,是程序设计的最高实现,以至于写代码时就往设计模式上凑,最终写出的代码冗余沉重,让人很难懂;而鄙弃设计模式的人实用至上,认为写出的代码能实现业务功能就好,对设计模式理也不理,结果代码杂乱不堪,稍有改动就引出一大堆 BUG,跟别人解释实现时,别人听得云里雾里。

我认为设计模式就是一些定义,就像冒泡排序、快速排序这些名字一样,便于开发者之间的交流,特别是在代码中,如果你提到使用了XX模式,如果阅读你代码的人也了解这个设计模式,那么他了解你的实现也就更加简单了。像之前在不了解设计模式的概念时,我就已经在很多地方应用模板模式和策略模式了,但在向别人介绍代码实现时,我需要说一堆代码设计,别人还不一定能理解,如果以后再跟人交流时,我不需要解释很多,只说我实现了模板模式就OK了。而且学会并深入了解了设计模式,那么以后遇到适用设计模式的场景,就可以不用苦逼地一遍遍修改代码,而直接朝着最美的方向设计了。

所以深入学习设计模式也是学习程序设计中很多问题的普遍解决方式,也是学习程序员之前交流的专业词汇,意义还是挺重大的。

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

设计模式,Let's “Go”! (中)的更多相关文章

  1. 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)

    在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...

  2. 漫谈 GOF 设计模式在 Spring 框架中的实现

    原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 漫谈 GOF 设计模式在 Spring ...

  3. [Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  4. PageObject设计模式,在selenium自动化测试中的运用

    PageObject设计模式1. Web自动化测试框架(WebTestFramework)是基于Selenium框架且采用PageObject设计模式进行二次开发形成的框架. 2. web测试时,建议 ...

  5. 初探Java设计模式4:JDK中的设计模式

    JDK中设计模式 本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图.首先来个总结,具体的某个模式可以一个一个慢慢写,希望能对研究JDK和设计模式有所帮助.一.设计模式是什么(1)反复出现 ...

  6. 装饰器设计模式初探及Java中实际应用举例

    本篇随笔主要介绍用Java实现简单的装饰器设计模式: 先来看一下装饰器设计模式的类图:  从图中可以看到,我们可以装饰Component接口的任何实现类,而这些实现类也包括了装饰器本身,装饰器本身也可 ...

  7. GOF 的23种JAVA常用设计模式总结 02 UML中的类图与类图之间的关系

    统一建模语言UML 统一建模语言(Unified Modeling Language,UML)是用来设计软件蓝图的可视化建模语言,1997 年被国际对象管理组织(OMG)采纳为面向对象的建模语言的国际 ...

  8. 设计模式在 Spring 框架中的良好应用

    在开始正文之前,请你先思考几个问题: 你项目中有使用哪些 GOF 设计模式 说一说 GOF 23 种设计模式的设计理念 说说 Spring 框架中如何实现设计模式 假设我是面试官问起了你这些面试题,你 ...

  9. java基础课程笔记 static 主函数 静态工具类 classpath java文档注释 静态代码块 对象初始化过程 设计模式 继承 子父类中的函数 继承中的构造函数 对象转型 多态 封装 抽象类 final 接口 包 jar包

    Static那些事儿 Static关键字 被static修饰的变量成为静态变量(类变量) 作用:是一个修饰符,用于修饰成员(成员变量,成员方法) 1.被static修饰后的成员变量只有一份 2.当成员 ...

  10. 「补课」进行时:设计模式(5)——从 LOL 中学习代理模式

    1. 前文汇总 「补课」进行时:设计模式系列 2. 从 LOL 中学习代理模式 我是一个很喜欢玩游戏的人,虽然平时玩游戏的时间并不多,但我也是一个忠实的 LOL 的爱好者,就是段位有点惨不忍睹,常年倔 ...

随机推荐

  1. 浅谈web服务器的编写之http协议

    本书是介绍怎么编写一个Web服务器,而Web服务器是基于HTTP(HyperText Transfer Protocol)协议实现的,所以要实现一个Web服务器就必须了解HTTP协议,本章主要介绍HT ...

  2. 华为OJ之最长公共子序列

    题目描述: 对于两个给定的字符串,给出他们的最长公共子序列. 题目分析: 1,在之前的博文(http://www.cnblogs.com/yonguo123/p/6711360.html)中我们讨论了 ...

  3. 如何通过android代码获取LTE信息?

    最近为了成功得到LTE的信号强度,尝试了很多种方法: (1)通过解析signalstrength字符串,但是不同手机设备获得的字符串排列顺序不同,代码如下: private PhoneStateLis ...

  4. Jenkins中的一些问题解决(~~不断更新~~)

    请使用ctrl+F,查询页面中你需要查找的错误信息(注意空格的输入) 1.错误"error fetching remote repo origin" 本地有多个sshkey,导致构 ...

  5. java内存区域——深入理解JVM读书笔记

    本内容由<深入理解java虚拟机>的部分读书笔记整理而成,本读者计划连载. 通过如下图和文字介绍来了解几个运行时数据区的概念. 方法区:它是各个线程共享的区域,用于内存已被VM加载的类信息 ...

  6. IPSP问题

    场景:接触IPSP项目是个学习的过程,在此记录一些自己的认知,让自己更能全面的理解项目! 1 总结 1.1 日志追踪 IPSP工程所在的服务器有GW和Server之分,GW是连接外部服务器和serve ...

  7. java利用接口和适配器进行完全解耦--参考《thinking in java》

    一.当使用父子类来实现以下东西时,其实是用了向上转型,这段代码的确简单了很多,复用性也很好,但是我们会发现Apply.process()和Processor类耦合过紧,其实apply.process( ...

  8. 使用Node.js搭建静态资源服务器

    对于Node.js新手,搭建一个静态资源服务器是个不错的锻炼,从最简单的返回文件或错误开始,渐进增强,还可以逐步加深对http的理解.那就开始吧,让我们的双手沾满网络请求! Note: 当然在项目中如 ...

  9. Qt5构建出错问题解决办法

    我之前用的Qt其他版本,因为一些原因我更换了Qt版本,从Qt5.9.1又更换到之前用的Qt5.3.2,但是发现无法build,问题提示如下: 19:54:03: 为项目untitled执行步骤 ... ...

  10. mk框架,一个基于react、nodejs全栈框架

    在这个前端技术爆炸的时代,不自己写套开源框架出门都不好意思跟别人打招呼,作为一个前端领域的小学生,去年年初接触了react,之后一发不可收拾爱上了它,近期重构了自己去年开源的一个项目,废话到此结束句号 ...