访问者模式
本博客大部分内容来于免费在线学习设计模式
1:访问者模式访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。
2:访问者模式问题假如你的团队开发了一款能够使用巨型图像中地理信息的应用程序。图像中的每个节点既能代表复杂实体(例如一座城市),也能代表更精细的对象(例如工业区和旅游景点等)。如果节点代表的真实对象之间存在公路,那么这些节点就会相互连接。在程序内部,每个节点的类型都由其所属的类来表示,每个特定的节点则是一个对象。
一段时间后,你接到了实现将图像导出到 XML 文件中的任务。这些工作最初看上去非常简单。你计划为每个节点类添加导出函数,然后递归执行图像中每个节点的导出函数。解决方案简单且优雅:使用多态机制可以让导出方法的调用代码不会和具体的节点类相耦合。
但是架构师拒绝批准对已有节点类进行修改。他认为这些代码已经是产品了,不想冒险对其进行修改,因为修改可能会引入潜在的缺陷。他还质疑在节点类中包含导出 XML 文件的代码是否有意义。这些类的主要工作是处理地理数据。导出 XML 文件的代码放在这里并不合适。还有另一个原因,那就是在此项任务完成后, 营销部门很有可能会 ...
模板方法模式
本博客大部分内容来于免费在线学习设计模式
1:模板方法模式模板方法模式是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
2:模板方法问题在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。
这样的例子在生活中还有很多,例如,一个人每天会起床、吃饭、做事、睡觉等,其中“做事”的内容每天可能不同。我们把这些规定了流程或格式的实例定义成模板,允许使用者根据自己的需求去更新它,例如,简历模板、论文模板、Word 中模板文件等。
3:模板方法解决方案模板方法模式建议将算法分解为一系列步骤,然后将这些步骤改写为方法,最后在 “模板方法” 中依次调用这些方 ...
策略模式
本博客大部分内容来于免费在线学习设计模式
1:策略模式策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。
2:策略模式问题你设计了一款地图程序。我相信大家都用过地图app,而这些程序中提供了多种策略来进行导航。步行,公交车,地铁,骑行,自驾等多种方法。如果将这些算法全部写在一个类中,这个类的体积臃肿,对某个算法进行任何修改都会影响整个类,从而增加在已有正常运行代码中引入错误的风险。同时将花费大量时间在合并冲突上。
3:策略模式解决方案策略模式建议找出负责用许多不同方式完成特定任务的类, 然后将其中的算法抽取到一组被称为策略的独立类中。
名为上下文的原始类必须包含一个成员变量来存储对于每种策略的引用。上下文并不执行任务,而是将工作委派给已连接的策略对象。上下文不负责选择符合任务需要的算法——客户端会将所需策略传递给上下文。实际上,上下文并不十分了解策略,它会通过同样的通用接口与所有策略进行交互,而该接口只需暴露一个方法来触发所选策略中封装的算法即可。
因此,上下文可独立于具体策略。这样你就可在不修改上下文代码或其他策 ...
状态模式
本博客大部分内容来于免费在线学习设计模式
1:状态模式状态模式是一种行为设计模式,让你能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。
2:状态模式问题状态模式与有限状态机的概念紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。在任何一个特定状态中,程序的行为都不相同,且可瞬间从一个状态切换到另一个状态。不过,根据当前状态,程序可能会切换到另外一种状态,也可能会保持当前状态不变。这些数量有限且预先定义的状态切换规则被称为转移。
对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else 或 switch-case 语句来做状态判断,再进行不同情况的处理。但是显然这种做法对复杂的状态判断存在天然弊端,条件判断语句会过于臃肿,可读性差,且不具备扩展性,维护难度也大。且增加新的状态时要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。
3:状态模式解决方案状态模式建议为对象的所有可能状态新建一个类,然后将所有状态的对应行为抽取到这些类中。
原始对象被称为上下文(context),它 ...
备忘录模式
本博客大部分内容来于免费在线学习设计模式
1:备忘录模式备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
2:备忘录模式问题在我们的日常生活中,撤销操作已经是每个编辑程序不可或缺的一部分了。一个程序如果没有撤销的能力。对于这一程序的用户体验将造成极大影响。那么撤销功能怎么实现呢?你选择采用直接的方式来实现该功能:程序在执行任何操作前会记录所有的对象状态,并将其保存下来。当用户此后需要撤销某个操作时,程序将从历史记录中获取最近的快照,然后使用它来恢复所有对象的状态。
如何生成一个快照呢?你需要遍历对象的所有成员变量并将其数值复制保存。但只有当对象对其内容没有严格访问权限限制的情况下,你才能使用该方式。不过很遗憾,绝大部分对象会使用私有成员变量来存储重要数据,这样别人就无法轻易查看其中的内容。
现在先暂时忽略这个问题,假设所有对象的成员变量都可以任意访问。这样你可以随时生成对象快照,但是这里还有另外一个很严重的问题-未来你可能添加一些成员变量,那么你将不得不对负责复制受影响对象状态的类进行更改
还有更多问题。让我们来考虑编辑器(Editor)状 ...
中介者模式
本博客大部分内容来于免费在线学习设计模式
1:中介者模式中介者模式是一种行为设计模式,能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
2:中介者模式问题在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如,每个人必须记住他(她)所有朋友的电话;而且,朋友中如果有人的电话修改了,他(她)必须让其他所有的朋友一起修改,这叫作“牵一发而动全身”,非常复杂。
3:中介者模式解决方案中介者模式建议你停止组件之间的直接交流并使其相互独立。这些组件必须调用特殊的中介者对象,通过中介者对象重定向调用行为,以间接的方式进行合作。最终,组件仅依赖于一个中介者类,无需与多个其他组件相耦合。
如果把这种“网状结构”改为“星形结构”的话,将大大降低它们之间的“耦合性”,这时只要找一个“中介者”就可以了。如前面所说的“每个人必须记住所有朋友电话”的问题,只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。这样的例子还有很多,例如,你刚刚参加工作想租房,可以找“房屋 ...
命令模式
本博客大部分内容来于免费在线学习设计模式
1:命令模式命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
2:命令模式问题假如你当前有一个列表页面需要渲染,当页面加载时需要请求数据,点击重置按钮时也需要请求页面数据,搜索数据也可以根据这个接口来请求数据。那么你怎么处理呢?是将数据的实现类复制多次,还是用其他方法呢?
3:命令模式解决方案很显然,在我们的实际使用中,是将数据请求和数据实现分离。将请求的所有细节(例如调用的对象、方法名称和参数列表)抽取出来组成命令类,该类中仅包含一个用于触发请求的方法。
在现实生活中,命令模式的例子也很多。比如看电视时,我们只需要轻轻一按遥控器就能完成频道的切换,这就是命令模式,将换台请求和换台处理完全解耦了。电视机遥控器(命令发送者)通过按钮(具体命令)来遥控电视机(命令接收者)。
再比如,我们去餐厅吃饭,菜单不是等到客人来了之后才定制的,而是已经预先配置好的。这样,客人来了就只需要点菜,而不是任由客人临时定制。餐厅提供 ...
观察者模式
本博客大部分内容来于免费在线学习设计模式
1:观察者模式观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察”该对象的其他对象。
2:观察者模式问题在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。拿双十一举例:如果某一商品决定在双十一当天零点进行大促销,如果他选择不通知任何人,那么他这一件商品的销量就只有听天由命了,一件都卖不去也说停;如果他选择通知所有浏览过这件商品的人,也许在这些人里有想买这件商品的人会选择购买,但是也会有很多不需要这件商品的人收到骚扰。在生活中,他们是怎么解决这件事的呢?
3:观察者模式解决方案在生活中,这些购物软件给店铺提供了一个渠道:对于那些关注过这家店铺,或者在这家店铺购买过的商品的潜在用户。店家可以通过软件提供的消息推送方式,或者购买记录的个人信息(虽然各种短信也挺骚扰的)。告诉你:我要降价了,快来买哦。这样店家也达成通知用户提高销量的目的,买家也可以低价买入需要的物品。
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象 ...
责任链模式
本博客大部分内容来于免费在线学习设计模式
1:责任链模式责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
2:责任链模式问题在日常生活中,请假,出差,申请活动等等。一件事可能需要经过多个对象的处理。举个例子:你写了一个办公程序,最初设置的是只需要部门主管同意,后面又逐渐增加人事,领导等等很多步骤。现在需要另外增加另一项功能,也需要这些审批手续(也可能是部分)。这一段代码怎么写呢?直接复制代码吗,本来每次增加步骤都会使代码更加臃肿,再对这些臃肿的代码进行复制,系统会变成怎样呢?
3:责任链模式解决方案责任链会将特定行为转换为被称作处理者的独立对象。在上述示例中,每个审批步骤都可被抽取为仅有单个方法的类,并执行审批操作。 请求及其数据则会被作为参数传递给该方法。
模式建议你将这些处理者连成一条链。链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理。
最重要的是:处理者可以决定不再沿着链传递请求, ...
迭代器模式
本博客大部分内容来于免费在线学习设计模式
1:迭代器模式迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素。
2:迭代器模式问题在现实生活以及程序设计中,经常要访问一个聚合对象中的各个元素,如“数据结构”中的链表遍历,通常的做法是将链表的创建和遍历都放在同一个类中,但这种方式不利于程序的扩展,如果要更换遍历方法就必须修改程序源代码,这违背了 “开闭原则”。而且不断向集合中添加遍历算法会模糊其 “高效存储数据” 的主要职责。 此外, 有些算法可能是根据特定应用订制的, 将其加入泛型集合类中会显得非常奇怪。
另一方面, 使用多种集合的客户端代码可能并不关心存储数据的方式。 不过由于集合提供不同的元素访问方式, 你的代码将不得不与特定集合类进行耦合。
既然将遍历方法封装在聚合类中不可取,那么聚合类中不提供遍历方法,将遍历方法由用户自己实现是否可行呢?答案是同样不可取,因为这种方式会存在两个缺点:
暴露了聚合类的内部表示,使其数据不安全;
增加了客户的负担。
3:迭代器模式解决方案迭代器模式的主要思想是将集合的遍历行为抽取为单独 ...