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

* { 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”! (中)

时间: 2024-10-17 01:45:08

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

浅谈设计模式的学习(中)

在<浅谈设计模式的学习(上)>中我说到了设计模式的基石-----抽象思维.为什么需要抽象思维呢?因为越抽象就越不容易出错,就像有些领导人说话:坚持改革开放.但怎么算坚持改革开放呢,没有具体的标准,因事而异,所以就不容易违背这个坚持改革开放的原则了. 3.学习设计模式,要保持抽象的思维     什么是抽象思维呢?真的不好说,抽象的东西往往难以说明白,听了也难以搞明白,还是通过具体的例子来说吧 有这么一个学生请假的场景,如果请假时间一天以内则有班长批准就可以了,三天以内则需要老师批准,超过三天就得

设计模式之设计原则(中)

接口隔离原则(Interface Segregation Principle ),简称ISP:该原则核心思想就是客户端不应该被强迫实现一些不会使用的接口,应该把胖接口中的方法分组,然后用多个接口来代替,每一个接口只服务与一个子模块.这个跟上次分享的单一职责原则类似. 设计接口隔离原则的目的:当我们设计应用程序时,如果一个模块包含多个子模块,那我们应该正对该模块抽象.设想该模块由一个类实现,我们可以把系统抽象成一个接口,但是我们想要添加新的模块扩展程序时,如果要添加的模块只包含原来系统的一些子模块

Java 设计模式之模板方法开发中应用

模板方法差不多是Java设计模式中除单例之外的另一种非常简单也是我们在写程序时非常常用的一种方法了.以至于当你看到模板方法的设计模式时你会感觉到,这不是我在程序中经常用到的方法么. 定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类不可以改变一个算法的结构即可重定义该算法的某些特定步骤. 下面是我总结的模板方法中具体的代码实现通用框架 1:抽象的模板类: package template; public abstract class AbstractClass { protect

MVC设计模式在唯品会网站中的应用

在刚刚过去的4.19唯品会活动中,我相信有很多人和我一样都参与了这个活动.当今社会,网上购物已经成了人们生活中不可缺少的一部分,今天让我们一起来看下MVC设计模式在唯品会网站中的应用. 我们平时在唯品会网站购物的时候,点击商品页面的加入购物车图标,然后商品就直接加入到购物车列表中,不管用户是否登录.然后我们换了一台设备,发现该网站我们之前在另一台设备上加入购物车的商品不存在.由此可以推断出:购物车列表的内容不是存放在数据库,而是在cookie中.所以购物车功能实现是在客户端实现的.购物车的功能有

JS设计模式入门和框架中的实践

JS设计模式入门和框架中的实践 在编写JS代码的过程中,运用一定的设计模式可以让我们的代码更加优雅.灵活. 下面笔者就结合诸如redux的subscribe.ES6的class.vue里面的$dispatch.jquery里面的on/off来给大家简单介绍下设计模式在这些库.语法和框架中的使用. 设计模式解决的问题 设计模式并不是很玄乎的知识,很多同学在编写JS代码的时候已经在不经意间用了不少设计模式了. 笔者认为把设计模式单独抽象出来探讨,就和算法中抽象出来冒泡.排序一样,是为了描述一种常用的

JavaScript 设计模式入门和框架中的实践 http://www.codeceo.com/article/javascript-design-pattern.html

在编写JS代码的过程中,运用一定的设计模式可以让我们的代码更加优雅.灵活. 下面笔者就结合诸如redux的subscribe.ES6的class.vue里面的$dispatch.jquery里面的on/off来给大家简单介绍下设计模式在这些库.语法和框架中的使用. 设计模式解决的问题 设计模式并不是很玄乎的知识,很多同学在编写JS代码的时候已经在不经意间用了不少设计模式了. 笔者认为把设计模式单独抽象出来探讨,就和算法中抽象出来冒泡.排序一样,是为了描述一种常用的JS pattern. 通过研习

MVC设计模式在游戏开发中的应用

一 定义 MVC即Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写. MVC是一种"前端"的设计模式. MVC的目的是:希望View和Model分离,当某一方改变时,而另一个方不必随之改变的. 例如,Java EE平台,iOS都是典型的基于MVC思想思想的,那么我们怎么在游戏设计中使用MVC模式呢. 二 MVC架构详解 1 模型Model 一直推荐一种思想:"所有的开发都是以数据位中心".在MV

《设计模式》一书中的23种设计模式

设计模式一书中提及了下面23种设计模式: AbstractFactory:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. Adapter:将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. Bridge:将抽象部分与它的实现部分分离,使它们都可以独立地变化. Builder:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. ChainofResponsibility:为解除请求的

[系列汇总] - 二十三种设计模式(持续更新中&hellip;)

摘要 最近在读GOF的Design Patterns: Elements of Reusable Object-Oriented Software(设计模式:可复用面向对象软件的基础),学习前辈们的经验来增加自己的编码设计能力.在学习的过程中,会把我从书上学到的知识以及自己的理解写到这里.一方面能够巩固自己学到的东西同时方便以后的复习,另一方面是希望能够帮助到那些跟我一样不大了解设计模式的人. 我理解的设计模式不是一套固定的代码,更多的是一种设计理念.它能够帮助我们解决特定的设计问题,使我们的程

设计模式在实际开发中的应用

分析功能:1.接到项目后要先分析好模块,分析好模块后再从模块里分析功能,把一个大的项目分成N个模块再把模块分析成N个功能点,把每个功能点都进行封装,有一个管理类进行管理. 代码逻辑分工 代码要做到层层管理,一个类管理着另外的一个些管理类,管理类里面又要管理封装一些功能点.做这一部分的时候建议使用观察者设计模式,定义 一个接口父类,让后通过不同的功能子类来基础接口父类,最后通过调用接口父类来管理子类. 2.要做到功能和流程区分,字段和逻辑区别. 这里就是代码实现是要注意点地方,代码实现时要注意到功