软件设计与体系结构 5-设计模式-2_第1页
软件设计与体系结构 5-设计模式-2_第2页
软件设计与体系结构 5-设计模式-2_第3页
软件设计与体系结构 5-设计模式-2_第4页
软件设计与体系结构 5-设计模式-2_第5页
已阅读5页,还剩131页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

5-设计模式Agenda设计模式之创建型设计模式之结构型设计模式之行为型设计模式之行为型我们知道,创建型设计模式主要解决“对象的创建”问题,结构型设计模式主要解决“类或对象的组合”问题,那行为型设计模式主要解决的就是“类或对象之间的交互”问题。行为型模式比较多,有11种,它们分别是:观察者模式、模板模式、策略模式、职责链模式、迭代器模式、状态模式、访问者模式、备忘录模式、命令模式、解释器模式、中介模式设计模式之行为型-观察者模式观察者模式是一个非常常用且影响巨大的设计模式,又称为发布-订阅模式。观察者模式应用广泛,影响深远,变种繁多。观察者模式(ObserverPattern)定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都可以得到通知并自动更新。设计模式之行为型-观察者模式(2)使用场景当你的业务符合订阅-发布这种场景时考虑这个模式。观察者模式将观察者和被观察者代码解耦。观察者模式的应用场景非常广泛,小到代码层面的解耦,大到架构层面的系统解耦,再或者一些产品的设计思路,都有这种模式的影子,比如邮件订阅、RSSFeeds,本质上都是观察者模式。设计模式之行为型-观察者模式不同的应用场景和需求下,这个模式也有截然不同的实现方式:有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。同步阻塞是最经典的实现方式,主要是为了代码解耦;异步非阻塞除了能实现代码解耦之外,还能提高代码的执行效率;进程间的观察者模式解耦更加彻底,一般是基于消息队列来实现,用来实现不同进程间的被观察者和观察者之间的交互。设计模式之行为型-观察者模式框架的作用有隐藏实现细节,降低开发难度,实现代码复用,解耦业务与非业务代码,让程序员聚焦业务开发。针对异步非阻塞观察者模式,我们也可以将它抽象成EventBus框架来达到这样的效果。EventBus翻译为“事件总线”,它提供了实现观察者模式的骨架代码。我们可以基于此框架非常容易地在自己的业务场景中实现观察者模式,不需要从零开始开发。设计模式之行为型-观察者模式程序猿前两天到北京出差见了一个大学同学,两人撸烤串、喝啤酒、忆往昔、互相吹捧一番...酒过三巡,同学突然说:你知道吗?当年你拼命追求的女神秋香离婚了...提前转移了财产,现在秋香那叫一个惨...程序猿陷入了那些峥嵘岁月...当年程序猿和码农都喜欢上了秋香,那时校内网风头正盛,程序猿和码农都订阅了上官的的校内网消息,女神的一条想法,就是程序猿和码农行动的命令...这个案例对应到程序上就是程序猿和码农都在观察秋香的状态,秋香的每一条状态改变都通过校内网通知了程序猿和码农,于是他们根据这个事件做出行动。设计模式之行为型-观察者模式第一步,确定被观察者,或者叫订阅主题。首先是秋香这个类,先定义一个接口,很简单,包含一个用来订阅的方法add和取消订阅的方法remove。还有一个当状态发生改变时,用来通知其观察者的方法notifyState

设计模式之行为型-观察者模式接下来是其实现类,也非常简单,其持有一个对其感兴趣的观察者集合,当状态发生改变时就循环通知每个观察者。设计模式之行为型-观察者模式第二步,观察者,或者叫订阅者。先定义一个观察者接口,里面只有一个方法,观察者就是在这个方法里面接收被观察者发送的状态改变通知。设计模式之行为型-观察者模式设计模式之行为型-观察者模式可以看到,在update方法中,接收到女神的通知后,根据不同的状态做出了相应的动作。码农类差不多。设计模式之行为型-观察者模式第三步,客户端的使用。客户端调用时,先给被观察者通过add添加观察者,也就是让程序猿和码农订阅秋香的状态,以便于秋香状态改变时可以得到通知。最后使用notifyState来通知观察者状态改变了。如果某个观察者不再对被观察者感兴趣,直接使用remove方法取消订阅即可。最后程序猿被秋香伤透了心,从此程序猿就不再关心秋香的状态了,直接使用remove方法取消订阅。

设计模式之行为型-观察者模式设计模式之行为型-观察者模式设计模式之行为型-观察者模式(4)总结:观察者模式的应用非常广泛,例如在各种消息中间件中,如kafka、RabitMQ等,例如RxJava等等。其实Java从1.0就对观察者模式进行了支持,提供了两个类型java.util.Observable和java.util.Observer。但其在Java9时候被标记为废弃状态,所以我们这里也就不提了,感兴趣的小伙伴可以去看看当前由于各种框架和第三方开源库的使用设计模式之行为型-观察者模式程序设计的要求被降的很低,大部分人终日都在写胶水代码和业务代码,什么设计模式,压根不知道,不知道也照样写代码...。这个是IT产业化不可逆转的趋势,不然为什么IT从业人员被划归为新型民工的行列了呢?就是因为我们正在变成工地上按照设计图纸一块一块垒砖的农民工的样子。不过我们也不应该妄自菲薄,搬砖是为了生活,不断探寻是为了梦想...设计模式之行为型-模板模式模板方法模式非常好理解,因为它特别贴近于我们的日常生活。顾名思义就是给出一个模板,大家按照模板各自去发挥。常常听一些“牛人”吹嘘:我的成功可以被复制!然后就告诉你第一步怎么干,第二步怎么干,第三步怎么干。。。但是10个人去按照他说的模板去做,却会有10种不同的结果,就像此次要谈论的模板方法模式一样。模板方法模式(TemplateMethodPattern)是在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中,使得子类可以在不改变一个算法的结构前提下即可重定义该算法的某些特定步骤。设计模式之行为型-模板模式(2)使用场景模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。这里的“算法”,我们可以理解为广义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“模板”,包含算法骨架的方法就是“模板方法”,这也是模板方法模式名字的由来。设计模式之行为型-模板模式模板模式有两大作用:复用和扩展。其中复用指的是,所有的子类可以复用父类中提供的模板方法的代码。扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。除此之外,我们还讲到回调。它跟模板模式具有相同的作用:代码复用和扩展。在一些框架、类库、组件等的设计中经常会用到,比如JdbcTemplate就是用了回调。相对于普通的函数调用,回调是一种双向调用关系。设计模式之行为型-模板模式A类事先注册某个函数F到B类,A类在调用B类的P函数的时候,B类反过来调用A类注册给它的F函数。这里的F函数就是“回调函数”。A调用B,B反过来又调用A,这种调用机制就叫作“回调”。回调可以细分为同步回调和异步回调。从应用场景上来看,同步回调看起来更像模板模式,异步回调看起来更像观察者模式。回调跟模板模式的区别,更多的是在代码实现上,而非应用场景上。回调基于组合关系来实现,模板模式基于继承关系来实现。回调比模板模式更加灵活。设计模式之行为型-模板模式这个设计模式一般在最初写代码的时候基本上不会预先想到的,都是在后期不断重构的过程中被提炼出来的。简单来说就是:当你发现你写了两个或者多个几乎一模一样的类,只是有些方法的实现方式不一致的时候,你就要停下来想想了:如果你又发现在使用这些类的地方调用方法顺序都一样,不要犹豫请使用模板方法模式重构吧。设计模式之行为型-模板模式直播行业是2017年互联网行业的风口,有熊猫直播、映客直播、陌陌直播、虎牙直播。。。说是全民直播也不为过。攻城狮的老板也想借着风上天,于是也加入了直播行业大军。小公司不可能自己开发一套直播的基础架构系统,实力不允许,于是就想到了接入第三方的直播SDK:刚开始接入了腾讯的直播SDK,后来由于不稳定又要同时接入金山的SDK,而且要做到可以互相切换。设计模式之行为型-模板模式当攻城狮带着程序猿日夜赶工,一个月后把这个功能实现后发现:这重复代码太多了,得重构,不然老板哪天又要接其他家的SDK可咋办,总不能把几乎一模一样的代码再写一遍吧。因为用户看直播是有一套固定的模板流程的:登录---进入房间---获取音视频流---观看---停止音视频流---退出房间。虽然两套SDK每一个步骤的实现方式不同,但是基本都是遵循同一套流程。攻城狮猛然发现,这不就是给模板方法模式准备的场景嘛,于是乎撸起袖子就干了!设计模式之行为型-模板模式模板方法模式关键点如下:一个模板类LivePlay,里面有一个定义为final的模板方法seeLivePlay().多个模板实现类。第一步:先定义一个模板类LivePlay,如下代码片段所示,其中的seeLivePlay()就是所谓的模板方法,为了不被子类overwrite,它被设置为final的,其定义了一个算法骨架。其中的login()是一个实体方法,里面是通用逻辑,所有的子类都是一样的。

设计模式之行为型-模板模式四个被abstract修饰的是抽象方法,这些方法是需要子类去根据自己的实际算法实现的,而pushVideoStream()方法有一个默认的空实现,这个一般称为钩子方法,设计用来被其中部分需要的子类overwrite。例如腾讯直播SDK提供了旁路推流的功能,而金山的没有提供,那么腾讯直播类就可以选择overwrite这个钩子方法,提供自己的实现。

设计模式之行为型-模板模式设计模式之行为型-模板模式第二步:定义具体的实体类,根据情况overwrite相应的抽象方法和钩子方法。

设计模式之行为型-模板模式由于金山SDK没有提供了旁路推流的功能,所以它不用覆写pushVideoStream()这个钩子方法,而只需要overwrite抽象方法即可。

设计模式之行为型-模板模式第三步:客户端调用,我们根据后端返回的结果来决定使用哪家的SDK。设计模式之行为型-模板模式优点主要是提高了代码的复用度,而且很好的符合的“开闭原则”。缺点是设计模式的通病:类增多了;调用控制反转:一般情况下,程序的执行流是子类调用父类的方法,模板方法模式使得程序流程变成了父类调用子类方法,这个使得程序比较难以理解和跟踪。设计模式之行为型-模板模式模板方法模式很好的体现了好莱坞原则(HollywoodPrinciple):Don'tcallus,we'llcallyou。使得父类来控制程序流程,父类根据程序执行需要将子类的功能勾到父类中,程序流程倒置这个点需要花一点时间适应。最后还是要提一下悲伤的结局:程序猿猜对了开头却没有猜对结尾,在其带领手下一帮兄弟如火如荼的接入另一家服务商ucloud的直播SDK期间,老板破产跑路了,带没带小姨子真不清楚,但是财务王姐跟着跑了。。。设计模式之行为型-策略模式我们这个社会上的事情大概率都符合八二法则,软件领域也一样。例如你学习一门编程语言,工作中常用的类来来回回也就那么几十个。那么多设计模式,最常被人使用的也就那么几种,所以我们在做事情的时候应该首先着眼于那20%。策略模式算是设计模式中简单而又常用的了。策略模式(StrategyPattern)定义了一系列的算法,并将每一个算法封装起来,使他们可以相互替换。设计模式之行为型-策略模式(2)使用场景当你写代码的时候发现一个操作有好多种实现方法,而你需要根据不同的情况使用if-else等分支结构来确定使用哪种实现方式的时候,想一想这个模式。策略模式定义一组算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指调用算法的代码)。策略模式用来解耦策略的定义、创建、使用。实际上,一个完整的策略模式就是由这三个部分组成的。设计模式之行为型-策略模式策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。策略的创建由工厂类来完成,封装策略创建的细节。策略模式包含一组策略可选,客户端代码选择使用哪个策略,有两种确定方法:编译时静态确定和运行时动态确定。其中,“运行时动态确定”才是策略模式最典型的应用场景。在实际的项目开发中,策略模式也比较常用。设计模式之行为型-策略模式最常见的应用场景是,利用它来避免冗长的if-else或switch分支判断。不过,它的作用还不止如此。它也可以像模板模式那样,提供框架的扩展点等等。实际上,策略模式主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入bug的风险。设计模式之行为型-策略模式2030年的2月14号,攻城狮和程序媛约好在“天津眼”约定终身,攻城狮打扮一番后准备出发,此时问题来了:是坐公交去呢,还是打滴滴快车呢?天气看起来也不错,要不骑共享单车吧,省钱还锻炼身体。对应到编程领域就是:目前有三种策略可以实现一个特定的目的,使用何种策略取决于调用者(客户端)。设计模式之行为型-策略模式如果我们正常写代码,平时也应该这样,首先保证把功能正确的实现了,然后慢慢重构,设计模式都是在不断的重构当中应用的。攻城狮会调用goToTianJinEye()方法,根据自己的实际情况,选择某一种出行方式。

设计模式之行为型-策略模式设计模式之行为型-策略模式那么这么写有什么弊端呢?第一:每一种出行方式的交通花费的计算方式都写在了TrafficFeeCalculator类中,这个类承担的职责较多,违反了单一职责原则。第二:假如攻城狮突然想自己开车去,那就需要修改goToTianJinEye这个方法了。违反了开闭原则。以上的场景非常适合使用策略模式,将多种不同的实现算法封装,然后客户端根据不同策略分别调用相应的算法。

设计模式之行为型-策略模式第一步:封装不同的实现算法,首先定义一个策略接口,规定算法的同一操作。设计模式之行为型-策略模式第二步:封装各个算法。设计模式之行为型-策略模式设计模式之行为型-策略模式设计模式之行为型-策略模式优点:降低了算法类的职责,使各个算法可以独立变化并互相替换。而且使得增加新的算法变的很容易,降低了对原有系统的侵入,最终使得程序可扩展可维护性增强。缺点:所有设计模式的通病,类增多了,程序从局部来看变的更复杂了。设计模式之行为型-策略模式是不是感觉讲设计模式时都有一个特点,使用了设计模式反而比不使用设计模式使程序看起来更加复杂,而不是更加简单?那是我们的示例都是无实际使用意义的示例代码,而实际中的软件项目可能会非常庞大和复杂一个大型程序是不断迭代出来的,一开始肯定不长那样,程序员日常接到一个开发任务也不要过多的想,这个我应该用个什么设计模式呀?先把功能实现了,然后回头看看有没有遵循面向对象编程6大原则,如果没有遵守想想怎么改进,然后设计模式就登场了。设计模式之行为型-职责链模式责任链模式是一个相对比较简单的模式,它的名字已经非常好的暗示了其工作原理。每个处理器互相首尾连接在一起成为一条链,然后任务顺着这条链往下传,直到被某个处理器处理掉。责任链模式(ChainOfResponsibilityPattern)避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。设计模式之行为型-职责链模式(2)使用场景一个请求需要被多个对象中的某一个处理,但是到底是哪个对象必须在运行时根据条件决定。在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过A处理器处理,然后再把请求传递给B处理器,B处理器处理完后再传递给C处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。设计模式之行为型-职责链模式(2)使用场景在实际中,对这个模式的变体是请求不会中途终止传递,而是会被所有的处理器都处理一遍。职责链模式常用在框架开发中,用来实现过滤器、拦截器功能,让框架的使用者在不需要修改框架源码的情况下,添加新的过滤、拦截功能。这也体现了OCP的设计原则。设计模式之行为型-职责链模式责任链模式唯一的难点就是怎么将很多处理器对象连成一条链?程序猿本来是干Android开发的,最近公司想让他把iOS的活也干了,但是Windows笔记本不能开发iOS,所以程序猿提出买一台Mac笔记本电脑。这花钱的事需要领导审批,而每个领导权限不一样,能够审批的最大金额有限制。程序猿首先肯定是向自己的小组leader提出,但是由于金额太大,超出了他的审批权限。于是小组领导就去找自己的领导,部门经理,但是部门经理也权限不够,最后到了CFO那里。程序猿遇到的情况就非常适合使用责任链模式。设计模式之行为型-职责链模式他这个预算申请的请求,事先不知道会由哪层领导处理,而各层领导的审批职责就好像铁链一样连接在一起,一个预算请求沿着这条链一直往上传...让我们用代码来实现上面的场景吧。第一,设计一个所有处理器都要实现的接口。其中setNextHandler(BudgetHandler)方法负责设置下一个处理器,以便在自己不能处理此请求的情况下,将请求交给下一个处理器。handle(int)方法负责处理请求。

设计模式之行为型-职责链模式设计模式之行为型-职责链模式设计模式之行为型-职责链模式设计模式之行为型-职责链模式客户端每个处理器都建好了,那么怎么才能让他们连成链呢?这就是客户端的责任了。设计模式之行为型-职责链模式首先,程序猿不知道谁最终会批准这笔预算,但是他知道入口肯定是他的小组领导,小组领导上一级就是经理,再上一级是CFO。所以在Handler中使用setNextHandler方法指定下一个Handler,最后由于CFO是最后一个处理器,所以我们就不设置Handler。最终程序猿拿到了自己心仪的Mac笔记本电脑.

设计模式之行为型-职责链模式(4)总结责任链模式要点:Handler接口持有它自己的类型,通过set方法或者构造函数将责任链上的下一个处理器赋值进去;客户端负责将各个处理器连成链,而且必然知道链上的第一个处理器,通过调用它的handle方法触发处理流程。注意千万不能将链搞成一个环(将最后一个处理的下一个handler设置为第一个),那样就无法结束了。设计模式之行为型-职责链模式(4)总结优点是命令发出者与执行者解耦。一个命令可以被多个处理器执行,例如各种框架中的拦截器。缺点是设计模式通病:类增多了。如果组链时候不合理,可能导致请求得不到执行,还有可能将链变成一个环,请求在里面循环,永远都完不了。

设计模式之行为型-迭代器模式迭代器模式如此常用,以至于很多编程语言都默认实现了此模式,所以虽然我们天天都在用迭代器模式,但却很少有自己实现的机会。其核心动机是为了在迭代一个容器对象的同时不暴露其内部细节,这啥意思呢?例如ArrayList类,当我们需要迭代它的元素的时候,我们不可能将其内部存储元素用的数据结构,例如数组,暴露给用户。那样的话不仅将来更换数据结构变的不可能,而且如果将内部细节暴露给了客户端,那么就无法控制客户端对其行为了。设计模式之行为型-迭代器模式(2)使用场景在Java开发中,当你要你要实现自己的容器类,且要迭代里面的元素时。换句话还可以说,当你要使自己的类支持foreach操作的时候使用此模式。在Java中没有必要自己实现这个模式,因为Java类库默认支持了此模式,所以此处我们也以Java官方类库为例谈论一下,因为我想写一些有用的东西,而不是华而不实的东西。迭代器模式(IteratorPattern)提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示。设计模式之行为型-迭代器模式迭代器模式也叫游标模式,它用来遍历集合对象。这里说的“集合对象”,我们也可以叫“容器”“聚合对象”,实际上就是包含一组对象的对象,比如,数组、链表、树、图、跳表。迭代器模式主要作用是解耦容器代码和遍历代码。大部分编程语言都提供了现成的迭代器可以使用,我们不需要从零开始开发。设计模式之行为型-迭代器模式遍历集合一般有三种方式:for循环、foreach循环、迭代器遍历。后两种本质上属于一种,都可以看作迭代器遍历。相对于for循环遍历,利用迭代器来遍历有3个优势:迭代器模式封装集合内部的复杂数据结构,开发者不需要了解如何遍历,直接使用容器提供的迭代器即可;迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一;迭代器模式让添加新的遍历算法更加容易,更符合开闭原则。设计模式之行为型-迭代器模式(3)例子在我们上大学的时候,无论哪一科的老师都喜欢在课前点名,为什么会这样呢?是因为老师不知道自己班级有几名学生吗?当然不是,恰恰是因为老师明知道自己班级有多少学生但放眼望去到场的却寥寥无几...“毕业多年,现在想想真的很怀念自己的大学生活,只恨当年为什么不拼命学习,拼命做一些有意义的事,我们的青春啊...”老师点名肯定是从头点到尾,对班里的每一个学生进行迭代...设计模式之行为型-迭代器模式第一步,写相应接口。由于Java已经天然支持了迭代器模式,我们直接使用就好了。主要涉及如下两个接口,看起来好简单对不对?对啊,本来也没多难。不过大概10年前吧,我第一次从C#中看到这两类似的玩意还是没有理解了。设计模式之行为型-迭代器模式如果我们要使自己的类支持迭代功能,只需要实现Iterable接口,而这个接口仅仅是要求实现一个方法,提供一个迭代器。而这个迭代器要实现Iterator接口,所以我们唯一需要做的就是提供一个实现了Iterator接口的类而已。第二步,实现。如下所示,我写了一个Class类,它实现了Iterable接口。然后内部类Itr作为迭代器。此类中我使用ArrayList作为内部数据结构,后期也可以换成数组,链表,树,图等等,而使用者却不用关心这些内部表示,这就是迭代器的妙处所在。

设计模式之行为型-迭代器模式设计模式之行为型-迭代器模式第三步,客户端使用相信有过点Java编程经验的用起这个类时都非常得心应手,因为他不知道已经用了多少次了。获取Class对象的迭代器,然后使用while循环迭代即可。设计模式之行为型-迭代器模式设计模式之行为型-状态模式状态模式在日常开发中是一个非常实用的模式,可以将你的代码逼格迅速提升一个档次,所以让我们开始今天的卓越之旅吧。定义对于初学者没啥用,因为字都认识却无法理解其中的含义。必须等学完了,回过头来看才能更加深刻的理解其含义。状态模式(StatePattern)当一个对象内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。设计模式之行为型-状态模式(2)使用场景你发现你的代码里面存在一个很长的ifelse列表,而这些分支都是因为不同状态下执行的操作不一样时考虑使用此模式。状态模式一般用来实现状态机,而状态机常用在游戏、工作流引擎等系统开发中。状态机又叫有限状态机,它由3个部分组成:状态、事件、动作。其中,事件也称为转移条件。事件触发状态的转移及动作的执行。不过,动作不是必须的,也可能只转移状态,不执行任何动作。针对状态机,我们总结了三种实现方式。设计模式之行为型-状态模式第一种实现方式叫分支逻辑法。利用if-else或者switch-case分支逻辑,参照状态转移图,将每一个状态转移原模原样地直译成代码。对于简单的状态机来说,这种实现方式最简单、最直接,是首选。第二种实现方式叫查表法。对于状态很多、状态转移比较复杂的状态机来说,查表法比较合适。通过二维数组来表示状态转移图,能极大地提高代码的可读性和可维护性。第三种实现方式就是利用状态模式。对于状态并不多、状态转移也比较简单,但事件触发执行的动作包含的业务逻辑可能比较复杂的状态机来说,我们首选这种实现方式。设计模式之行为型-状态模式(3)实例最近攻城狮又要过生日了,近两年他内心中是非常抗拒过生日的,因为每过一个生日就意味着自己又老一岁,离被辞退的35岁魔咒又近了一步。可惜时间是不以人的意志为转移的,任何人都阻止不了时间的流逝,所以该过还的过。令攻城狮比较欣慰的时,这次过生日老婆送了他一个自己一直想要的机械键盘作为生日礼物...秋香于是在攻城狮生日前3天在京东上下了一个单...自从下单以来,攻城狮天天看物流状态信息,心心念念着自己的机械键盘快点到...设计模式之行为型-状态模式这个物流系统就很适合使用状态模式来开发,因为此过程存在很多不同的状态,例如接单,出库,运输,送货,收货,评价等等。而订单在每个不同的状态下的操作可能都不一样,例如在接单状态下,商家就需要通知仓库拣货,通知用户等等操作,其他状态类似。第一步,定义一个状态接口,此接口定义各个状态的统一操作接口。设计模式之行为型-状态模式第二步,定义一个物流Context类,此类持有一个LogisticsState的引用,负责在流程中保持并切换状态。

设计模式之行为型-状态模式第三,实现各种状态类。接单状态类,其需要实现LogisticsState接口。

设计模式之行为型-状态模式设计模式之行为型-状态模式可见,我们将每个状态下要做的具体动作封装到了每个状态类中,我们只需要切换不同的状态即可。如果不使用状态模式,我们的代码中可能会出现很长的ifelse列表,这样就不便于扩展和修改了。(4)总结该模式的要点:必须要有一个Context类,这个类持有State接口,负责保持并切换当前的状态。状态模式没有定义在哪里进行状态转换,本例是在Context类进行的,也有人在具体的State类中转换。设计模式之行为型-状态模式当使用Context类切换状态时,状态类之间互相不认识,他们直接的依赖关系应该由客户端负责。例如,只有在接单状态的操作完成后才应该切换到出库状态,那么出库状态就对接单状态有了依赖,这个依赖顺序应该由客户端负责,而不是在状态内判断。当使用具体的State类切换时,状态直接就可能互相认识,一个状态执行完就自动切换到了另一个状态去了。

设计模式之行为型-状态模式优点是增强了程序的可扩展性,因为我们很容易添加一个State增强了程序的封装性,每个状态的操作都被封装到了一个状态类中。状态模式与策略模式的UML类图都是一样的,从表面上看他们非常相似。特别是将状态切换任务放在Context中做的时候就更像了,但是其背后的思想却非常不同。策略模式定义了一组可互相代替的算法,这一组算法对象完成的是同一个任务,只是使用的方式不同例如同样是亿万富翁,马云通过卖东西实现,而王思聪通过继承实现。状态模式中不同的状态完成的任务完全不一样。

设计模式之行为型-访问者模式访问者模式可以说是GOF23中设计模式中最复杂的一个,但日常开发中使用频率却不高。增删改查虽然简单,却是大部分程序员日常主要工作,是可以混饭吃的家伙式。你技术再牛逼,企业用不到,那对于企业来说也没用,所以说合适的才是最好的,但不常用不等于没有用。访问者模式试图解决如下问题:一个类农场里面包含各种元素,例如有大雁、狗子、鸭子。设计模式之行为型-访问者模式而每个元素的操作却经常变换,一会让大雁排成一字,一会让大雁排成人字。当大雁排成一字的时候狗子要排成S形状,鸭子要排成A形状,当大雁排成人字时候狗子要叫两声,鸭子要跳起来...。但对农场这类有要求,第一:可以迭代这些元素,第二:里面的元素不能频繁变动,你不能一会把鸭子杀了吃了,一会又买回一匹马...如果是这样的话就不适合使用Visitor模式。如果我们不采用设计模式,那么就要频繁的修改这些元素类,违背了开闭原则,降低代码的可维护和扩展性。设计模式之行为型-访问者模式(2)使用场景当你有个类,里面的包含各种类型的元素,这个类结构比较稳定,不会经常增删不同类型的元素。而需要经常给这些元素添加新的操作的时候,考虑使用此设计模式。访问者模式(VisitorPattern)封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于其内部各个元素的新操作。设计模式之行为型-访问者模式访问者模式允许一个或者多个操作应用到一组对象上,设计意图是解耦操作和对象本身,保持类职责单一、满足开闭原则以及应对代码的复杂性。对于访问者模式,学习的主要难点在代码实现。而代码实现比较复杂的主要原因是,函数重载在大部分面向对象编程语言中是静态绑定的。也就是说,调用类的哪个重载函数,是在编译期间,由参数的声明类型决定的,而非运行时,根据参数的实际类型决定的。设计模式之行为型-访问者模式正是因为代码实现难理解,所以,在项目中应用这种模式,会导致代码的可读性比较差。如果你的同事不了解这种设计模式,可能就会读不懂、维护不了你写的代码。所以,除非不得已,不要使用这种模式。设计模式之行为型-访问者模式攻城狮刚参加工作那会由于社会经验不足误入了一个大忽悠公司,公司老板不舍得花钱就给公司招了3个人,一个HR、一个程序员、一个测试,但关键是老板总想追风口,啥都想做,一会社交,一会短视频。攻城狮多次提出说人太少,申请加几个人,至少加个保洁阿姨啊,不然每天都自己打扫卫生。设计模式之行为型-访问者模式每到此时老板就画大饼:你现在刚毕业正是要奋斗的时候,此时不奋斗什么时候奋斗?过两年公司上市了,你作为元老就财富自由拉...这个场景就很适合使用访问者模式:大忽悠公司结构很稳定,老板舍不得花钱招人,总共就那么3个人,还是3种角色,即只有3个元素。大忽悠公司老板想法多,这就要求这3个人承担各种新技能,即不断的给元素增加新的算法。设计模式之行为型-访问者模式第一步:构建Element毕竟改变的是元素的算法,所以这里我们先构建元素。类只有一个accept方法,它需要一个访问者接口类型的参数。

设计模式之行为型-访问者模式构建3个公司员工的实现类设计模式之行为型-访问者模式构建3个公司员工的实现类HR类:同上,省略。

设计模式之行为型-访问者模式第二步:构建ObjectStructure。BigCompany类里面需要包含相对稳定的元素(老板就招这3个人,再也不肯招人),而且要求可以对这些元素迭代访问。此处我们以集合存储3位员工。

设计模式之行为型-访问者模式设计模式之行为型-访问者模式第三步:构建Visitor。Visitor接口里面一般会存在与各元素对应的visit方法,例如此例我们有3个角色,所以这里就有3个方法。设计模式之行为型-访问者模式Visitor实现类。因为老板觉得社交是人类永恒的需求,所以开始想做社交App,他觉得他能成为微信第二。这就相当于要为每一个元素定义一套新的算法,让程序员仿照微信开发设计app,让测试完成即时通信的测试,让人力发软文。设计模式之行为型-访问者模式设计模式之行为型-访问者模式过了一段时间,老板又觉的短视频很火,又要做短视频,这就要求给每一员工增加一套新的算法。设计模式之行为型-访问者模式设计模式之行为型-访问者模式虽然老板的需求变化这么快,但至始至终我们只是在增加新的Visitor实现类,而没有去修改任何一个Element类,这就很好的符合了开闭原则。(4)总结访问者模式要点总结:准确识别出Visitor实用的场景,如果一个对象结构不稳定决不可使用,不然在增删元素时改动将非常巨大。对象结构中的元素要可以迭代访问Visitor里一般存在与元素个数相同的visit方法。元素通过accept方法通过this将自己传递给了Visitor。设计模式之行为型-备忘录模式备忘录模式听起来特别高深,其实可能写过几年代码的都不知不觉的用了很多次了。模式的名称其实已经很形象的反映出其作用了:就是为了在某一时刻把当前的状态记录下来,以后再恢复到那时的状态。备忘录模式(MementoPattern)是在不破坏封闭的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,从而可以将对象恢复到原先保存的状态。设计模式之行为型-备忘录模式(2)使用场景当你正在开发一个功能,这个功能需要存档的时候就应该想到它。例如游戏,文档编辑器等等,都需要在你下次重新打开的时候恢复到你关闭它时候的状态。备忘录模式也叫快照模式,具体来说,就是在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。这个模式的定义表达了两部分内容:一部分是,存储副本以便后期恢复;另一部分是,要在不违背封装原则的前提下,进行对象的备份和恢复。设计模式之行为型-备忘录模式备忘录模式的应用场景也比较明确和有限,主要用来防丢失、撤销、恢复等。它跟平时我们常说的“备份”很相似。两者的主要区别在于,备忘录模式更侧重于代码的设计和实现,备份更侧重架构设计或产品设计。对于大对象的备份来说,备份占用的存储空间会比较大,备份和恢复的耗时会比较长。针对这个问题,不同的业务场景有不同的处理方式。比如,只备份必要的恢复信息,结合最新的数据来恢复;再比如,全量备份和增量备份相结合,低频全量备份,高频增量备份,两者结合来做恢复。设计模式之行为型-备忘录模式程序猿在享元模式那集帮他儿子开发了个五子棋游戏,儿子玩过几次后提出了一个痛点:儿子:老爸,我经常玩到一半的时候妈妈就喊我去睡觉,然后我睡醒了打开它就变成新的了,你能不能在我睡觉的时候把它存起来,那样我玩的时候就能从上次停下来的地方开始了...。程序猿:听着那小子一直巴巴,程序猿陷入了沉思:养个儿子真费劲,这么小就使唤老子,长大了还的帮着娶媳妇,关键是房子那么贵,以后还的带孙子...这要是个闺女多好...儿子:老爸,你干啥呢,你听见我说话了吗...程序猿:听见拉,听见啦,我这就给你弄,但是你以后拉粑粑让你妈擦屁股啊,不要叫我了,听见没?程序猿思索了一下,此情此景正是备忘录模式的用武之地。设计模式之行为型-备忘录模式第一步:定义Originator。这个类是游戏类,我们就是要保存和恢复游戏进度。它内部提供了两个方法,一个对外提供备忘录,里面封装了其要恢复的内部状态。另一个是从外部接收备忘录,用来恢复内部状态。可能有的同学要问了:为什么要这么搞呢?直接写个setter不行吗?其实核心思想还是为了封装。这里的currentScore是GameOriginator的内部状态,我们不愿意对外暴露,所以使用另一个对象包起来。这样的内部状态一般会有很多,这里做了简化。

设计模式之行为型-备忘录模式构建备忘录Memento这个类最简单,其基本上就是一个POJO。它不包含业务逻辑,只包含状态数据,结构由要保存的状态类决定。例如我们这里只保存一个内部状态,游戏分数。

设计模式之行为型-备忘录模式构建CareTaker如果说备忘录模式有一点点技巧的话,也就是这个类了。CareTaker相对于Originator来说是一个外部组件,它帮助Originator保存了状态,相当于Originator将自己某一个时刻的状态保存到了外部。当我们要保存状态时,使用此类的saveMemento。当我们要恢复状态时,使用此类的getMemento.

设计模式之行为型-备忘录模式设计模式之行为型-备忘录模式设计模式之行为型-备忘录模式(5)总结技术要点:首先识别出Originator需要保存的状态,然后构建一个备忘录类Memento;Originator需要提供两个方法,一个用于对外提供包含内部状态的备忘录,一个用于使用外部传递进来的备忘录恢复内部状态;CareTaker负责保存备忘录,并提供访问方法。

设计模式之行为型-命令模式命令模式(CommandPattern)将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或记录日志,以及支持可撤销的操作。设计模式之行为型-命令模式(2)使用场景反复强调,使用场景非常重要!因为纵使你有十八般武器,不知道什么时候用也是白搭。从定义上我们就可以看出其可以解决的问题。1)当需要将各种执行的动作抽象出来,使用时通过不同的参数来决定执行哪个对象;2)当某个或者某些操作需要支持撤销的场景;3)当要对操作过程记录日志,以便后期通过日志将操作过程重新做一遍时;4)当某个操作需要支持事务操作的时候。设计模式之行为型-命令模式21世纪,人类社会的科技日新月异,狂人马斯克正在努力在2050年前将100万人类送往火星殖民。同时人类社会在其他方面也在努力创新,比如人工智能,这不最近有一家科技公司尽然制造出了高智慧机器人,还支持订制,真是太贴心了。攻城狮很兴奋,订制了两款:John号与Luke号。攻城狮随后会向机器人发出各种各样的指令,这个就很适合使用命令模式。

设计模式之行为型-命令模式第一步:声明一个命令接口(Command)。设计模式之行为型-命令模式第二步:构建那些可以具体完成命令的角色(Receiver)。攻城狮发出的那些命令需要具体的角色来执行,这就用到订制的那两个机器人啦。先构建一个John号机器人:设计模式之行为型-命令模式此处的John号机器人只支持了两个功能:唱歌和弹琴,如果需要更多功能,需再构建一个Luke号机器人。第三步:构建各种具体命令(ConcreteCommand)。先构建一个唱歌命令,其要实现Command接口。因为只有John机器人提供这个功能,所以我们要在这个命令内部使用JohnReceiver

来具体执行。

设计模式之行为型-命令模式再构建一个弹琴命令,与前面唱歌命令类似。设计模式之行为型-命令模式还想看跳舞,所以再构建一个跳舞命令。由于只有Luke号机器人提供这个能力,所以此处的执行者就变成了LukeReceiver.

设计模式之行为型-命令模式我们看到,此命令里面除了具体执行命令的LukeReceiver,还包含了命令执行时需要的数据,例如跳舞时长。这也是命令模式需要注意的地方,具体的命令类里不止包含具体执行命令的那个对象,也包含相关数据。

设计模式之行为型-命令模式第四步:构建命令的调用者(Invoker)机器人和命令都准备好了,那么具体怎么发送呢?这就是Invoker的角色了。攻城狮买这两个机器人时还带了一个智能语音控制器,他通过这个控制器就可以发出各种命令了。设计模式之行为型-命令模式第五步:客户端使用:让john先把琴弹起来,再把歌唱起来...还有,让luke来跳舞...

设计模式之行为型-命令模式设计模式之行为型-命令模式命令模式的要点如下:1)Command接口非常简单,通常只有一个execute方法,如果要支持撤销操作的话,再加一个unexecute方法;2)每个具体的命令类内部封装了实际执行命令的那个类(Recevier),或者那些类,以及执行需要的数据;3)每个具体命

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论