设计模式,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 }
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)

介绍

责任链模式:将请求处理者串成“链”依次尝试处理请求,以此解耦请求和处理者;

  • 责任链模式将任务处理者划分先后次序,依次尝试,直到任务被处理;
  • 每个处理者存储自己的下一环;任务开始时选择最靠前的处理者试图处理任务;
  • 在遇到自己无法处理的情况,传递给自己的下一环来处理;

场景

  • 适用于单个任务,多个处理者;
  • 需要依次尝试处理者;

实现

  1. 公司里 leader、经理和CEO有不同额度的报销限额;
  2. leader报销不了的金额交给经理,而经理将自己处理不了的给CEO处理;
  3. 张三要报销200元,leader就能批准;
  4. 李四要报销8000元,leader报销不了,就交给经理,经理也处理不了,最后交给CEO报销;

蝇量模式(Flyweight)

介绍

蝇量模式:使用一个对象存储和模拟多个虚拟对象,大大减少多个对象的内存占用。

  • 实例化多个相似实例会占用较多内存空间,蝇量模式使用一个对象类变量保存多个对象的属性,以一个对象控制多个对象;
  • 蝇量模式可以极大地减少内存占用,也可以方便对多个对象进行统一管理
  • 实例一旦实现了蝇量模式,那么单个实例就无法再独立拥有不同的行为;

场景

  • 有很多相似对象,拥有相同的属性项和方法;
  • 多个对象只会被统一调用;

实现

  • 在一片森林中,有很多大树,他们都只有高度一个属性;
  • 将多个大树的属性保存一个森林对象的 map 中;
  • 调用森林的砍伐方法,砍伐森林中所有的树;

解释器模式(Intepreter)

介绍

解释器模式:定义一种方法和对应的解释器,使用解释器解释此方法的语句来执行;

  • 解释器模式需要上下文类来定义和存储上下文,解释器类用来将语句来翻译成可执行程序;
  • 解释器扩展和改变文化非常简单,构建完成后可以很方便地数据格式;
  • 解释器模式会将非终结表达式递归解释,直到解释为终结符表达式;

场景

  • 解释器模式适用于数据结构不规则,但数据要素相同的情况;
  • 语法不能太复杂,复杂的最好使用解释形语言来实现以降低复杂性;

实现

  1. 在php中,php环境是上下文;
  2. 字符串值不能再向下解释了,如 "hello" "greeting" 都是终结符;
  3. 在上下文中定义了两个变量 $greeting = "hello"; $test = "greeting";
  4. 现在来解释变量 $$test = "hello";

中介者模式(Mediator)

介绍

中介者模式:通过一个中介对象封装多个对象之间的交互,解耦各个对象之前的相互依赖;

  • 对象之间通过中介者进行交互,不必再显示调用目标对象;
  • 中介者对对象之间的关系进行了封装,减少了对象之间的耦合,使得对象可以独立改变和复用;
  • 中介者模式与适配器模式和代理模式的不同之处:三者都通过中间对象解决对象之间的沟通问题,但他们要解决的问题和解决问题的对象都不同;

场景

  • 中介者模式适合多对多的对象交互情况;
  • 中介者适合对象之间交互较多,依赖复杂的情况;

实现

  1. 联合国作为多个国家之间的中间人存在,各国家之间通过联合国沟通;
  2. 法国和韩国尝试通过联合国隔空对话;
  3. 他们双方只向联合国喊话,并从联合国处获取对方国家的回应;

备忘录模式(Memento)

介绍

备忘录模式:使用一个备忘录对象记录并保存对象内部状态,并能随时恢复到保存的状态;

  • 备忘录对象是一个类似于目标对象的轻量级对象,它保存着目标对象的可变属性;
  • 备忘录保管者可以保存多个备忘录,并将对象恢复到任一时刻; ###场景
  • 备忘录模式适用于需要保存对象历史状态用以支持撤销的场景;

实现

  1. 时光掌控者保存着许多人类世界的“时间快照”;
  2. 小明18岁时身高175,体重70,时光掌控者此时获取小明的信息产生了一个快照;
  3. 小明在不停地长大,80岁时身高170,体重65;
  4. 时光掌控者选择小明18岁的快照对小时进行了恢复,小明又回到了18岁;

原型模式(Prototype)

介绍

原型模式:通过复制原型对象修改属性的方式来快速创建新对象;

  • 原型模式通过抽象多个对象的相同属性和方法来设置一个原型;
  • 原型模式可以通过原型对象设置对象的基本属性,减少创建出的对象的开放;
  • 原型模式使得调用者只知道对象的原型而不必了解创建过程即可创建一个新对象;

场景

  • 原型模式适用于对象较大或创建过程较复杂的情况;
  • 适用于需要创建多个有共同“原型”的对象,也即它们拥有大部分共同属性;

实现

  1. 据说国家仪仗队的队员都是 年龄20岁、身高180、体重72kg的男性士兵;
  2. 抽象一个“年龄20岁、身高180、体重72kg”的人作为仪仗队员的“原型”;
  3. 创建一个仪仗队员原型,并设置姓名来产生一个真实的仪仗队员对象;

访问者模式(Visitor)

介绍

访问者模式:将对一些对象的访问过程抽象出类,以实现在不改变对象的前提下对这些对象添加操作;

  • 访问者模式分离对象的数据结构和数据操作
  • 访问者模式将数据的访问方法集中到一个类中作为访问者,便于对数据访问的统一管理;
  • 如果数据有添加或删除,需要修改多个访问者;

场景

  • 访问者模式适用于数据结构稳定的类;
  • 对对象的同一种数据有多种不同的操作方式;

实现

  1. 超市里的商品都有 名称和价格 两种属性,顾客使用购物车保存了要买的商品;
  2. 设置一个打印机访问者,访问并打印顾客购物车内的商品名称;
  3. 如果要添加一个商品价格计算器,只需要实现与打印机相同的访问者接口,访问并计算购物车中商品的价格;

小结

最后说一下设计模式的分类,根据设计模式所针对的问题,将设计模式分为三类:

  • 创建型,创建型模式针对对象的创建。包括:工厂模式、单例模式、生成器模式、原型模式;
  • 行为型,行为型模式针对对象的行为,如对象之间的通信、职责分配。包括:策略模式、观察者模式、状态模式、模板模式、命令模式、迭代器模式、责任链模式、中介者模式、解释器模式、备忘录模式、访问者模式。
  • 结构型,结构型模式针对如何实现对象的结构。包括:装饰者模式、适配器模式、外观模式、桥接模式、组合模式、代理者模式、蝇量模式。

设计模式的目标,是用来解决通用问题的。一个项目也不可能只有一种问题,所以在真正的使用中,还是要将不同的设计模式组合使用,总而言之:多想、多写

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

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

时间: 2024-09-30 14:49:54

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

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

时间过得真快啊,不知不觉又要周末了,借这个周末时间.把<浅谈设计模式的学习(下)>补上吧. 在<浅谈设计模式的学习(中)>中,说到了保持抽象的思维.接下来说一下第四点,做一个分享,也记录一下自己的学习历程. 4.学习设计模式,就不要把它看的太认真    设计模式是一个编程思想,它不是具体的代码套路.举个例子说明一下: 由于家传,接触到了一些中国的传统武术.当我与那些不懂传统武术的人交流的时候,他们总是认为中国的传统武术都是些套路.花架子,只是用来好看.在他们认为,两人打架,别人出拳

探索MVP(Model-View-Presenter)设计模式在SharePoint平台下的实现

探索MVP(Model-View-Presenter)设计模式在SharePoint平台下的实现 对于SharePoint Developers来说,往往会过多的去关注SharePoint平台和工具,而把设计模式和代码的可测试性放在了一个较低的优先级.这并不是说SharePoint Developers对设计模式不感兴趣,而是缺乏在SharePoint平台下使用设计模式的经验.所以本篇Blog正如题目所示:探索MVP(Model-View-Presenter)设计模式在SharePoint平台下

Java面试题下

这部分主要是开源Java EE框架方面的内容,包括hibernate.MyBatis.spring.Spring MVC等,由于Struts 2已经是明日黄花,在这里就不讨论Struts 2的面试题,如果需要了解相关内容,可以参考我的另一篇文章<Java面试题集(86-115)>.此外,这篇文章还对企业应用架构.大型网站架构和应用服务器优化等内容进行了简单的探讨,这些内容相信对面试会很有帮助. 126.什么是ORM?答:对象关系映射(Object-Relational Mapping,简称OR

javascript设计模式详解之命令模式

每种设计模式的出现都是为了弥补语言在某方面的不足,解决特定环境下的问题.思想是相通的.只不过不同的设计语言有其特定的实现.对javascript这种动态语言来说,弱类型的特性,与生俱来的多态性,导致某些设计模式不自觉的我们都在使用.只不过没有对应起来罢了.本文就力求以精简的语言去介绍下设计模式这个高大上的概念.相信会在看完某个设计模式之后有原来如此的感慨. 一.基本概念与使用场景: 基本概念: 将请求封装成对象,分离命令接受者和发起者之间的耦合. 命令执行之前在执行对象中传入接受者.主要目的相互

23种设计模式导航

Java设计模式 写个导航页,一方面使调理更清晰一些,另一方面也能直观看到自己的进度. 总述设计模式还真不知道怎么下嘴,之前看的大话设计模式也不是java版的,不过既然是总结自己的学习收获,总得有个归纳的章法,就暂且搜索一个常规分类贴下来,待后续边总结边修改. 1.创建型模式 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory) 创建者模式(Builder) 原型模式(Prototype) 单例模式(Singleton) 2.结构型模式 外观模式(Fac

【设计模式之禅 第2版】读书笔记

自己练习的源码地址:https://git.oschina.net/snnhoo/DesignPattern.git  欢迎推送 第一章 单一职责原则 简称SRP:Single Responsibility Principle 定义:应该有且仅有一个原因引起类的变更 好处: 类复杂度降低,职责明确 可读性高 可维护性高 变更引起风险低 接口设计要单一,实现要根据情况,方法也适用单一职责 第二章 里氏替换原则 定义:父类能出现的地方就能用子类,且不会产生任何异常,但是反过来则不行,有子类出现的地方

闲话iOS的MVC设计模式

模式是经验知识的复制应用.MVC设计模式在不同的开发平台有不同阐述和应用.目前在网路上可以搜索出java版本.c++版本.c#版本的,也有ios版本的.我这里也发布这篇关于MVC设计模式的文章,用我的缘走你的路. 写在前面的话 若然不用设计模式,难道就不能开发设计程序了吗?不然.那么设计模式给我们带来什么呢?如果你不学习别人总结出来的设计模式,就能轻松.快捷.真正地解决问题,而且还乐意再来一次,我相信你不需要别人的设计模式了.如果??某些问题,让你很挠头,让你不敢再回首,不妨借助别人总结出来的设

Android 设计模式-单例模式

Android 设计模式-单例模式 什么情况下需要单例模式? 一些类提供公共功能供别人调用,本身不会处理业务逻辑 类会被许多类和线程调用 设计单例模式 public class Singleton{ private static Singleton mSingleton; private Singleton(){ } public static Singleton getInstance(){ if(mSingleton == null){ mSingleton = new Singleton(

元素模式是单一关系的表现,是设计模式不可再分的最小单元

当我们在软件设计中想应用设计模式时,往往是凭借设计模式的名字和需求有点类似,之后就尝试着将模式生搬硬套到其中.而真正去理解设计模式往往变得比较困难,很多书籍也仅仅是用不同方法来降低模式记忆的强度.难道设计模式不能从更加细微的层面去理解吗?当然可以,设计模式就像可以再分解的化合物一般是可在分解,这种再分解后的模式叫做元素模式(elemental design patterns , EDP). 元素模式重申了一个非常重要的思想:模式是概念,而不是结构.GoF也这样认为:"假设某语言是面向过程的语言,

设计模式概述

面向对象设计原则 单一职责原则 Single Responsibility Principle 从软件变化的角度来看.就一个类而言,应该仅有一个让他发生变化的原因. 正确抽象是实现SRP的关键 开闭原则 Open-Closed Principle 软件实体(类.模块.函数等等)应该是能够扩展的,可是不可改动的 开闭原则是面向对象设计的核心,抽象是OCP的核心 总有一些功能不能通过扩展来实现须要改动源码.不要over-consider OCP 里氏替换原则 Liskov Substitution