* { 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 }
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/7506537.html 以防误人子弟。
正文开始:
责任链模式(Chain of Responsibility)
介绍
责任链模式:将请求处理者串成“链”
,依次尝试
处理请求,以此解耦请求和处理者;
- 责任链模式将任务处理者划分先后次序,依次尝试,直到任务被处理;
- 每个处理者
存储自己的下一环
;任务开始时选择最靠前的处理者试图处理任务; - 在遇到自己无法处理的情况,传递给自己的下一环来处理;
场景
- 适用于单个任务,多个处理者;
- 需要依次尝试处理者;
实现
- 公司里 leader、经理和CEO有不同额度的报销限额;
- leader报销不了的金额交给经理,而经理将自己处理不了的给CEO处理;
- 张三要报销200元,leader就能批准;
- 李四要报销8000元,leader报销不了,就交给经理,经理也处理不了,最后交给CEO报销;
蝇量模式(Flyweight)
介绍
蝇量模式:使用一个对象
来存储和模拟多个虚拟对象
,大大减少多个对象的内存占用。
- 实例化多个相似实例会占用较多内存空间,蝇量模式使用一个对象类变量保存多个对象的属性,以一个对象控制多个对象;
- 蝇量模式可以极大地减少内存占用,也可以方便对多个对象进行
统一管理
; - 实例一旦实现了蝇量模式,那么单个实例就无法再独立拥有不同的行为;
场景
- 有很多相似对象,拥有相同的属性项和方法;
- 多个对象只会被统一调用;
实现
- 在一片森林中,有很多大树,他们都只有高度一个属性;
- 将多个大树的属性保存一个森林对象的 map 中;
- 调用森林的砍伐方法,砍伐森林中所有的树;
解释器模式(Intepreter)
介绍
解释器模式:定义一种方法和对应的解释器
,使用解释器解释此方法的语句
来执行;
- 解释器模式需要上下文类来
定义和存储上下文
,解释器类用来将语句来翻译成可执行程序; - 解释器扩展和改变文化非常简单,构建完成后可以很方便地数据格式;
- 解释器模式会将非终结表达式
递归解释
,直到解释为终结符表达式;
场景
- 解释器模式适用于数据结构不规则,但数据要素相同的情况;
- 语法不能太复杂,复杂的最好使用解释形语言来实现以降低复杂性;
实现
- 在php中,php环境是上下文;
- 字符串值不能再向下解释了,如
"hello" "greeting"
都是终结符; - 在上下文中定义了两个变量
$greeting = "hello"; $test = "greeting";
- 现在来解释变量
$$test = "hello"
;
中介者模式(Mediator)
介绍
中介者模式:通过一个中介对象封装多个对象之间的交互
,解耦各个对象之前的相互依赖;
- 对象之间
通过中介者进行交互
,不必再显示调用目标对象; - 中介者对对象之间的关系进行了封装,减少了对象之间的耦合,使得对象可以独立改变和复用;
- 中介者模式与适配器模式和代理模式的不同之处:三者都通过中间对象解决对象之间的沟通问题,但他们要解决的问题和解决问题的对象都不同;
场景
- 中介者模式适合多对多的对象交互情况;
- 中介者适合对象之间交互较多,依赖复杂的情况;
实现
- 联合国作为多个国家之间的中间人存在,各国家之间通过联合国沟通;
- 法国和韩国尝试通过联合国隔空对话;
- 他们双方只向联合国喊话,并从联合国处获取对方国家的回应;
备忘录模式(Memento)
介绍
备忘录模式:使用一个备忘录对象记录并保存
对象内部状态,并能随时恢复
到保存的状态;
- 备忘录对象是一个类似于目标对象的轻量级对象,它保存着目标对象的可变属性;
- 备忘录保管者可以保存多个备忘录,并将对象恢复到任一时刻; ###场景
- 备忘录模式适用于需要保存对象历史状态用以支持撤销的场景;
实现
- 时光掌控者保存着许多人类世界的“时间快照”;
- 小明18岁时身高175,体重70,时光掌控者此时获取小明的信息产生了一个快照;
- 小明在不停地长大,80岁时身高170,体重65;
- 时光掌控者选择小明18岁的快照对小时进行了恢复,小明又回到了18岁;
原型模式(Prototype)
介绍
原型模式:通过复制原型对象
再修改属性
的方式来快速创建新对象;
- 原型模式通过
抽象多个对象的相同属性和方法
来设置一个原型; - 原型模式可以通过原型对象设置对象的基本属性,减少创建出的对象的开放;
- 原型模式使得调用者只知道对象的原型而不必了解创建过程即可创建一个新对象;
场景
- 原型模式适用于对象较大或创建过程较复杂的情况;
- 适用于需要创建多个有共同“原型”的对象,也即它们拥有大部分共同属性;
实现
- 据说国家仪仗队的队员都是 年龄20岁、身高180、体重72kg的男性士兵;
- 抽象一个“年龄20岁、身高180、体重72kg”的人作为仪仗队员的“原型”;
- 创建一个仪仗队员原型,并设置姓名来产生一个真实的仪仗队员对象;
访问者模式(Visitor)
介绍
访问者模式:将对一些对象的访问过程抽象出类
,以实现在不改变对象的前提下对这些对象添加操作;
- 访问者模式
分离对象的数据结构和数据操作
; - 访问者模式将数据的访问方法集中到一个类中作为访问者,便于对数据访问的统一管理;
- 如果数据有添加或删除,需要修改多个访问者;
场景
- 访问者模式适用于数据结构稳定的类;
- 对对象的同一种数据有多种不同的操作方式;
实现
- 超市里的商品都有 名称和价格 两种属性,顾客使用购物车保存了要买的商品;
- 设置一个打印机访问者,访问并打印顾客购物车内的商品名称;
- 如果要添加一个商品价格计算器,只需要实现与打印机相同的访问者接口,访问并计算购物车中商品的价格;
小结
最后说一下设计模式的分类,根据设计模式所针对的问题,将设计模式分为三类:
- 创建型,创建型模式针对对象的创建。包括:工厂模式、单例模式、生成器模式、原型模式;
- 行为型,行为型模式针对对象的行为,如对象之间的通信、职责分配。包括:策略模式、观察者模式、状态模式、模板模式、命令模式、迭代器模式、责任链模式、中介者模式、解释器模式、备忘录模式、访问者模式。
- 结构型,结构型模式针对如何实现对象的结构。包括:装饰者模式、适配器模式、外观模式、桥接模式、组合模式、代理者模式、蝇量模式。
设计模式的目标,是用来解决通用问题的。一个项目也不可能只有一种问题,所以在真正的使用中,还是要将不同的设计模式组合使用,总而言之:多想、多写
。
关于本文有什么问题可以在下面留言交流,如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。博客一直在更新,欢迎 关注 。
设计模式,Let's “Go”! (下)