设计模式复习课转写
自动语音识别整理稿,已去除时间戳并按段落合并。由于课堂录音存在口音、噪声和专有名词,个别词句仍可能需要结合 PPT 校订。
上半场
-
今天我们很想学习这个。
-
因为你说这个……再讲一遍,很无聊,你知道吗?
-
我自己都看到,从一篇文章上,这个……- 如果我把诸事点讲出来没有太直白,不够高层。
所以就讲一些新的东西但是在里面拍一些讲考的内容比较隐晦 取决于大家的感悟吧有一点但是可以肯定肯定是有价值的因为考卷我已经出好了所以讲的时候肯定是比较有目的性的可以讲一些内容其实如果说真的读习的话从刚刚我们在上这个新课的这种文件已经讲了很多跟原来那种相关的一些知识当然不是这个没事到事把冷汗炒烤肯定是希望能够给大家一些帮助尤其是在上到字的时候还能坚持上课也是很不容易特别是今天大家也知道比较是不行所以给大家一些好处然后第二个讲讲关于考试的一些题目我刚才讲了我们考试也不是为了特别钻考题所以考试考的主要还是比较先理解性的所以在答题的时候不需要太过专注一些细节比如说画设计图UML图的时候类的决策啊什么名词技术性啊什么的你其实也可以写一些类似比如说你
有的同学这个画的类图上面他也基本上这个决策应该叫什么名字啊或者什么的写出一些类型让别人知道你有多少的理解有一点很重要的就是我想说的就是特别在设计的时候很重要的是你要把你的设计意图说出来比如说我们这个答案肯定会考就是设计题肯定会让你使用一些设计模式去做一些主意这个时候很关键的一点就是你首先要把你用哪几个设计模式写出来你得写出来你用哪几个设计模式以前经常有同学这个搭起来就发这个类似的关键在我们这个题呢通常会讲是这个两个三个四个设计模式的联合使用所以他画了一得意的这个类型然后这个里面呢画得也太准确名字那一写不太说实话看不出他到底用了什么模式我只能这个尽可能的这个专项一下意想一下他用了什么能推上几个视频但这样的话其实可以推进好所以大家要把这个模式的
你用哪几个模式写出来第二个呢如果你不太确定这个模式到底长什么样至少最简单的比如说这个命令模式你用了你记不得他到底长什么样至少你把你记得的那几个重要的比如说有什么的有引口和什么的你可以这个在图上也标一下到底哪个视频大致上差不多了其实也差不多了不会扣太多所以这个很关键一定要画清楚最怕的就是一张黑图上面经常会看到很多题但是好多人一堆抽象类五六个抽象类下面的啪啪啪啪全是记者类我也看不出谁是谁所以这个时候就不理会了第二呢就是在这个注写的时候很多同学都非常的关注这个设计模式把这个设计模式推得很平衡但是呢对这个设计原则理解的不够深入尤其是就是这个模式体现了什么样的原则啊对吧什么原则才让你选择这个模式啊对这套这个原则和模式之间就相当于各列了前面最早讲的原则
后面他就推面模式我们在这个课上一开始还是要回顾一下设计原则这个设计原则相关的内容最主要的一条就是我们的设计原则都是面向可为互信和可服用性这个一定要非常地清楚然后呢在这个过程中间讲了哪些原则单一值的开支原则理事代换原则对吧依赖道长原则 接受隔离原则合成互动原则基比特法则这些你都要非常地熟悉能够这个掌握他们的这个含义等等同时呢这个你在这个使用的时候也要区分这些原则比如说通常问你问同学啊这个这个地方啊是为了达成什么原则好多同学都给我达成开支原则这个开支原则是一个目标对吧开支是一个目标这是当然达成开支原则但是你要回答的是这个更下面的原则比如说这个指导性的原则是最小支持原则这是一个指导性的原则很多地方也都可以用这个原则但是呢只有在小数的情况下它才是对的
别大多数情况下开支是个指导性原则它不是这个最根本的原则我们希望达成的这个回答是这个能够达到这个点上的比如说是单一值得还是合成性的封装原则这是一个基础的原则那么实现这个基础原则和指导性原则还有这个支线原则依赖到的原则合成性封装原则以及到的原则所以你要搞清楚它的这个关系搞清楚这个关系比如说啊这个可变性封装啊你可能就涉及到这个依赖到的原则合成性封装原则在这里面用了两条还是三条需要有一个明确的这个理解这个是这个设计原则相关的第二个呢就是关于这个设计模式这个设计模式我们一直都在讲这个软件设计模式那这个软件设计模式大家要注意一下其实软件模式并非仅限于这个设计模式你还包括了这个架构模式分析模式过手模式等等那这个时候其实大家考试的时候要看清楚这个是关于要考这个架构模式的
还是要考这个软件的这个设计模式那么其实两个地方都有对吧两个地方都有那同时呢这个大家要看一下这个前面讲的这些这个设计模式这个设计模式说到底要让你去运动这些设计模式所以呢我们这个设计题这个设计题关于设计模式只会有一道题但是呢它会是一个这个运动题在这个运动题中间呢会让你去解决一个具体的问题注意一下这个这是你有一点去确定的就是什么就是必然它出到了一个题所以呢必然它只有一个标本答案必然只有一个标本答案所以呢就必然就你要仔细的这个审题仔细的审题因为设计其实是可以有很多种设计方案前提是什么前提是这个约束你要图不清的情况所以你在这个看这个设计题的时候一定要注意你要知道我们的软件模式是对软件开发特定问题的解法的一种统一表示对吧它是一个问题的和解法但是呢
这个模式的基础除了这个问题的你不要去看它问题的描组有的同学一看到这个对象能够及时收到通知所以你要这样看到这个前提条件我们会在题目中当然题目不会说问题点点点条件点点点一不肯定是这个但是呢你要看到这个问题中间对于这个前提条件的描组什么是前提条件主要就是环境或者约束这个环境这个环境这个环境这个环境这个环境这个环境这个环境主要就是环境或者约束的条件环境或者约束的条件我有一些这个具体的约束我告诉你这个希望达成什么什么我们目前只有什么什么样的这个条件那这些其实都会影响到对具体的模式的原则所以这个是要仔细审题是最关键的不要一上来就有这个划则的意思到时候划完了之后改的时间都没有对吧你要先想清楚要是没几个模式第三个呢还有一个除了这个解法条件大家不要忘了
还有效果这个模式都有这个优缺点尤其是这个缺点它会影响去效果那我可以从这个效果上描述我不希望达成什么效果我希望达成什么效果那这个时候也会影响具体模式的使用所以这个时候大家一定要非常关注我们的这个软件模式不是一个简单的问题的解法而是一整套问题描述前提条件解法和效果优缺点以及意义对吧当然你还不可能破产了关联解法其他的相关模式对于模式联合使用会有很大的好处另外呢这个这个就不讲了另外呢就是设计模式的分类设计模式的分类我们一直其实每个模式都会讲这个设计模式的分类设计模式呢根据分类有两种一种是根据目的就是模式在做的对吧分为创建型结构型和行为型三种创建型就主要创建对象结构型主要处理类或对象的组合所以这个其实是用来创建新的类型的一种这个替代对吧那么行为型模式主要描述
类和对象怎样交互和怎样分配之等这个主要是用来用来应变应对变化的行为可以那为什么要分这个三种这个类型呢主要还是在模式的联合使用上创建型模式通常不会自己和自己联合但是创建型模式很容易和结构型和行为型进行这个联合使用联合使用行为型模式通常也很少自己和自己联合当然少数情况是有的哪些情况有的呢因为行为型模式中间有一些是和主要功能正交模式正交行为模式我们也讲过这个两个对吧它是可以一些联合使用但是呢其他情况下联合使用的不多最主要的就是这个结构型模式结构型模式所以你在联合使用中间是不是当然最主其实这都是一些大体真正的使用的时候还是要从这个问题和前几条件出手但是在大体问题结构型模式最容易通常来说结构型可以和创建型模式结构型可以和行为型模式结构型还可以和结构型一起用
因为大家都是这个组合而已所以这个结构型模式最灵活的所以你这样可以查一分类之后你就可以知道这个这个模式的这个联合使用它不是一个随意组合的关系它在各个类别之间实际上是有一些线相对而言组合的情形就稍微多当然另外从范围上使用就是这个处理这个类的关系还是对向之间的关系关系就分为类模式和对向模式那这个呢其实大家了解就好了对这个聚集使用关系不大然后最后就是我们讲的整个这些这个模式这些模式都在这个考试上可以多讲一句话这个设计这个设计大家讲第一个第一个重要的考点范围就是设计原则这个影响第二个主要的考试范围就是这个模式本身的理解模式本身的理解分成两种第一种是这个模式内部这个关键设计的这个关键设计比如说为什么这里要有一个接口为什么这里要有一个这样的角色这是它的第一个
第二个关键设计从设计原则上为什么它牺牲了这个开闭联合性为什么它能够要做到这个透明性等等都是一些设计考虑的设计模式相关的那么最后呢就是模式的这个联合使用模式的联合使用是我们的这个最大的考点主要的这个可能分叉就在这道题上就是这个最后一道设计题因为最后一道设计题一道题就有这个20分所以因为它能一下来没找对这个模式下来可能是这个所以这个怎么样去做好这个设计就往下往下你要去判断这个问题和前提条件那我们前面我也讲了这个这样讲太抽象所以呢找了一个书上的例子大家来看一下也作为一个新的内容当然也有可能也是考试内容都有可能反正你自己把握出来我们在讲模式的时候啊单一的模式实际上是可以使用但是呢更多的情况下但是在真正的这个设计中间是多个模式和同时使用同时使用
但是呢这种同时使用大家要注意一下它不是说我有一个问题东一个模式西一个模式而是这些模式会叠加在一起形成一个更加复杂的复合结构比如说我们很多 pattern它会形成新的 pattern我们把它叫做 compound pattern这个中文不太好翻这个 compound pattern中文应该叫什么组合也是组合模式但不是那个 compound pattern它是一个多个模式这个组合聚合在一起那么这个时候呢这样的一个这样的一个一旦它能够解决同一个问题并且呢前面我们讲过的如果说一个解决方案是反复出现的并能用于一般问题的它当然也能够做得上称作是一个 pattern所以模式的模式也是模式最经典的一个是什么NBC 对吧NBC 就是模式的模式当然它自己也成了一个模式
那么我们来看一下怎么会有这样的一个情形我们来看一下这个书上的这个题我们最早呢这个第一堂反正在讲设定模式的时候呢我们一开始就讲了这个有一个鸭子的例子大家应该还有一点印象对吧讲策略模式的时候我们有一个鸭子的例子那么在这个鸭子的例子中间呢我们做了一个策略叫做 crackable鸭叫这样的一个接口现在呢我们仍然做一个 crackable 接口这一次呢我们是从头开始做了我们把之前的设计好了我们要求所有的鸭子都实现一个 crackable 接口这个很容易理解因为鸭叫是因为在不同的鸭子中间不一样所以我们把它独立成一个接口叫做 crackable 接口那么这个 crackable 接口呢可以被我们的模拟器鸭子模拟器使用来调一个这个接口发出这个鸭叫的声音
不管是绿头鸭还是红头鸭等等都可以使用这个 crackable 接口都会使用这个 crackable 接口那么现在呢我们让每个鸭子都实现这个 crackable 接口比如说mallard duck 绿头鸭也实现这个 crackable 接口redhead duck 红头鸭也实现这个 crackable 接口他们呢都能够做一些行为前面我们讲过了这种方式因为它出现了重出代码对不对我们现在先不解决这个问题所以要求还没出现首先别管它要看民主的要求然后呢其他的鸭子比如说duncan也能够实现它是模仿的然后呢rubber duck也实现了所以呢我们现在做好了一个工具叫做 duck simulator这个 simulator 是干嘛呢它有一个 simulate 函数
这个 simulate 函数呢它又叫一个 simulate 子函数这个子函数里面就叫 duck 的 crack 方法所以呢它可以创建一系列的鸭子让每个鸭子叫起这个就是 simulate 函数所做的工作那现在这个设计好了现在呢就是新的需求就来了现在停播的要求是什么呢现在希望能够使用这个在任何使用鸭子的地方都能够使用一个叫做 goose 类goose 类这个 goose 类呢提供一个也是一个鹅叫鹅叫 hum这些都以生死它能够发出这个 hum 的声音然后那现在呢因为我们觉得geese 和 duck 是一样的所以我们希望能够在任何使用duck 的地方也能够使用 goose 类那我们如何使用哪个模式可以让 geese非常简单的在我们的 simulate 类和 duck 的一起使用
这个就是我们的第一个问题我们休息十分钟
下半场
这个地方需要用什么模式啊?
这个地方需要用什么模式来解决这个问题啊?
这个地方其实大家就要有这个身体啊。
这里边提中间最重要的一句话是什么?
就这里。
Use a goose anywhere we want to use a dot。
什么叫Use a goose anywhere we want?
就是说在所有的这些地方,有simulate的地方,是我们使用到dock,对吧?
这个simulate的这个地方,原来使用到dock,我们能够使用那个boost类。
使用这个boost。
所以这样一来的话,就可以看出这个非常直接的问题就是什么。
原来这个参数取代的是什么?
需要的是这个yas类型。
现在我们变成了boost类。
我们怎么样把这个boost类型匹配到这个yas类型呢?
是这个type类型,typeable类型。
能够匹配到typeable类型啊?
当然就是接口的不一致。
那只要能够完成接口的转换,那当然就原来使用typeable的地方,就能够使用boost。
那接口转换其实只有一个模式能够做这件事,这个类型。
所以这个地方就是非常明确的要使用这个试配器。
就是our simulatorexpects to see practical interfaces.Since keys aren’t practical,we can use an adapterto adapt the boost to that.对吧?
好,那现在关键第一个大家问题就解决了,所以你要答的第一点就是如果问你用什么模式,你就会答用试配器模式。
然后呢,接下来我们要做这个设计。
做设计最关键的一个是什么呢?
其实可以跟大家说一下。
最关键的,就是要找到接口。
找到接口是最关键的。
在这个问题中间,我们可以看到这个试配器,我们现在用的是什么?
用的是对象式配器。
对吧?用的对象式配器。
它的接口是谁啊?
就是这个topic。
最关键的这个接口就是topic,对不对?对吧?
这里就有一个接口,就是topic。
现在,只要确定了这个topic就完成了。
所以topic是谁啊?
是大壳类型的。
Catapult,对吧?
是Catapult类型。所以一般这个Catapult确定了啊,这里就是Catapult。
这里就是一个GooseAdapter,这里就是Goose。
所有的类型都确定了。
所以你现在要实现的很简单,就是做一个GooseAdapter。
它的接口呢,要用这个Catapult。
它和原来的这个设计都已经配合在一起了,对不对?
用Catapult。然后呢这个GooseAdapter组合了一个Goose对象。然后呢实现这个Catapult的Quant方法在里边调用Goose的方法。
整个这个设计就完了。
所以现在加以改你就可以创建一个Catapult的Goose对象。
在这个地方呢,用的是GooseAdapter里面封装一个Goose对象。
在Symbolic的地方呢,就可以使用这个Goose。
第一个问题就解决了。
那这只是一条需求,我们现在是拆开看的了。现在呢,作为一个整体我会有很多条需求。
第二条需求呢,是我们在这个系统之上,这个Pakalogis有一个这个专门研究压教的压教学者非常想去研究这个Pakalogis压教行为。
现在呢,Pakalogis希望做的事情就是要能够获得一群鸭子的所有的压教次数。
这是他的目标。
那么,我们具体要做什么呢?
虽然这是一句问话,但是呢,这里其实加了一个约束条件。我们现在是希望能够加上这个对压教的这样的一个Count技术的能力,但是呢,without having to change thePakalogis,我们希望不要去改变这个鸭子本身类。
所以,这是一个约束条件。没有这个约束条件实现的方式有很多的不同。不止一种有了这个约束条件之后,我们实现的方式实际上就被限制。
大家看一下,在这个需求下,我们要用哪个模式解决这个问题呢?
在这个条件下,用哪个模式去解决啊?
这个时候,其实刚才讲的这个时候,其实只有一个选择。在这个没有改变人类的情况下,增加一个类的额外的行为对吧?增加一个类的额外的行为。就是只有装饰。
装饰者的,大家想想,装饰者的定义本身就不重要。
所以,这里就可以想到,我们其实只需要使用一个装饰者模式,就能够对鸭子添加新的行为。
什么新的行为呢?就是Count。
然后呢,同时,因为装饰者所用的食材品就增加了一个包装类。
所以,它不需要改变原来的鸭子。
它不需要让这个鸭子类去实现新的接口。
或者,添加新的行为。
如果你当初开始想到,诶,我觉得要技术,所以呢,我用观察者,那就模仿一下刚才的例子。
它不需要让这个鸭子类去实现一个格外的接口。
它需要改变原来的类型。
那有同学说,装饰者也是一样的样子。
装饰者对于这个Decorator和Count,Decorator当然不管,Decorator大家注意一下啊,当我们使用一个模式的时候,我们会添加一些服务类。其实Decorator和,和我们刚才的这个适配器一样的,适配器中的这个Adapter和装饰模式中的Decorator一样,都是服务类,是可以额外添加的,不改变原来的设计。但是这个同学马上说,那还有一个问题。
这个,装饰的模式中间,这个背装饰对象,也就是我们的这个鸭子类啊,它需要什么,实现一个装饰接口。
这个Component,这个会不会改变呢?注意一下,还是一样的。你要弹一下,这个Component,Component的作用是什么?
Component的作用是,实现提供一个,让装饰对象和背装饰对象一个统一的接口,可以让它能够这个,无感的透明的,添加一个装饰者。所以Component的对象,其实它到底是谁,不重要。
它只要是背装饰者的一个接口这个接口能够提供它的主要功能行为就是所以你可以什么,附用已有的接口。
在这个例子中间,大概一个是一样的,我们要确定新的模式中间的这个接口是谁,接口对象是谁。
在这个新的模式中间,这个模式中间,最重要的接口只有一个,Component。
而且我讲了,Decorator都是可以额外添加的,所以你只要是关注这个Component这个Component是谁啊?
是Yas的一个接口,同时提供这个通用的行为,Operation我们设计中有没有啊?
有,是谁啊?Quackable所以这个时候,这个Component的接口,就可以附用原来Yas设计中的Quackable接口。因为这个Quackable接口正好是Yas的接口,同时Quackable接口提供QuackYas的用,正好是我们调用的模式,所以你可以再次附用Quackable接口。
所以这样一来的话,还是Implement Quackable所以现在我们的Quackable,大家可以看出来什么啊?
我们现在已经在上面用了两个模式装饰者和适配器,而且这两个模式都是独立的为什么啊?它有一个重叠的地方,装饰者的这个Component和适配器的Compute Interface是同一个接口所以我们现在就可以添加一个新的类,叫做QuackCompImplement Quackable,在上面呢诶,它既然是一个这个装饰者所以呢,它就可以封装一个Dock,同时添加一个Count行为我们把它设置成一个进采的原样所以可以对整个Yas群进行技术统计只要叫一次,现在Quack叫一次,就可以Number of Quacks加加它就可以技术了好,这样一来我们这个第二个设计就完成了这个就是两个模式两个使用现在呢,这个我可以再添加新的需求第三条需求QuackCounting is great,但是呢
我们希望这个去再了解一些新的我们发现呢发现在运行的过程中有很多问题,就是Too manyQuacks aren’t being counted有很多的Quacks没有被counted为什么没有被counted呢这个就是什么,你要了解就是试费器模式的一个主要缺点,我们也讲过试费器模式的主要缺点是什么是装饰与被装饰难以控制因为我们前面非常强调我很难控制这个对象是否会正确的装饰有可能他不装饰了有可能他没装饰这个是试费器模式而装饰者的主要缺点装饰者的主要缺点因为装饰过的对象和未装饰的对象或者装饰错的对象对用户来说都是透明的所以他并不知道这个装饰到底是什么问题,他只能得到一个最后的结论在我们的例子中间所以我们要分析为什么会有很多2-minute clock on the bin counter
肯定是他没装饰对吧你虽然提供了这个装饰功能但是装饰对象的装饰是要在客户代码中完成的就像这样你需要放一件quite counter然后把这个大小输给这个客户他是在客户代码中完成装饰所以就是这样的问题那现在就是说了我们现在要做一件事情那做一件事情我们希望他解决这个问题解决这个的问题怎么做呢这边讲了一个是什么效果就是讲了一个效果所以将来他就把这个使用的模式给限制死在这里要使用那种模式很简单其实这个很清楚是这个装饰者模式现在要做一个什么效果呢鸭子的创建和他的装饰要工装起来鸭子的创建和他的那么简单是什么创建性模式和我们的这个装饰者模式要联合使用所以你只要在创建性的模式中间选一个就好了那如果是封装创建过程的这个模式实际上有好几个有好几个但是大家看一下在我们这个
意思中间有没有复杂的创建过程那接下来剩下的只有那个复杂他也是什么呢其实要创建两类两个不同的产品组要创建两个不同的产品组一个呢是你在需要鸭子技术鸭子要技术的时候的装饰过的鸭子的产品组一个呢是你不需要技术的未装饰的样子的产品组在这个产品组下面又有很多的其他的产品所以这个时候我们就可以使用抽象工厂来解决这个问题那抽象工厂来解决这个问题之后关键最重要的是什么你要确定每一个接口是谁呀实际上你只要确定一个就是为什么呢因为这个抽象工厂模式中间又分成两部分原有的产品是原有的都是额外加的使用工厂模式的特点就是工厂都是额外加的工厂帮忙类是额外加的抽象工厂类也是额外加的对不对建造者也是额外加的既然是额外加的你都可以先新鲜加你只要确定已有设计中的部分如何联合
已有设计中的部分牵扯到的只有这个Affiliate到为什么呢那Affiliate Product是谁呀你发现Affiliate Product更加了Affiliate Product实际上只要提供一个产品接口是谁就无所谓只要能把这些产品组合起来就行你现在已经有了就是谁呀Affiliate Product对不对首先你做一个Affiliate Product然后你做一个Dark Factory在这个Dark Factory你有不技术的Create Dark然后你再做一个Counting Dark Factory做一个技术的在这个技术的Factory很重要的一个就是什么为每一个工厂方法为每一个工厂方法封装创建对象和装饰对象的过程封装创建对象和装饰对象的过程
封装创建对象和装饰对象的过程我前面也讲过了工厂方法和工厂和装饰者是经常联合使用的为什么因为装饰者有一个问题他其实虽然他是一个他是一个结构型模式所以结构型模式是什么是替代创建类型的但是呢装饰者结构型模式的主要问题就是装饰比较硬和而且结构型模式替代的过程中间创建对象的职责主要是由组合完成的这个组合是在刻铺代码中完成的所以他把创建过程分到了模式内的和模式使用代码中间的部分容易出现问题那怎么解决这个问题我们有一个专门封装创建的方法就是工厂方法所以装饰者模式和工厂方法经常联合使用那这样一来大家看到原来这一行代码是放在刻铺代码中间的现在呢我把它封装到了工厂方法中间之后他就不再是一个灵活的使用了你任何使用这个鸭子的过程都要通过创建一个Condent Country
然后由这个Condent Country要转回一个鸭子这样就可以保证当时会确切装饰于是呢这个方式就可以解决刚才的这个问题那大家马上又有一个疑问大家想想为什么我在讲这个第二个装饰者设计的时候是用约束条件来描述而在讲这个工厂这个的时候中央工厂的时候是用效果来描述呢因为很简单在讲装饰者的时候这个约束条件是设计的约束它不够强它已经能够让你这个工厂但是在这个工厂的这个过程中间虽然我们提供了这样的投降工厂你仍然有自主创建对象的能力所以你硬要去创建你说我就是不用这个工厂当然这个数据就硬到了那我怎么样保证你提供的时候不会出现这样的一些误解呢我就告诉你我现在要烘装但是没有第二个选择所以你不能这样做所以其实这个每一个描述都可以确定答案是这个唯一如果你解极的时候想到很多答案
说明你还是没有提供接下来这个还没完我们就添加一个第四个需求现在呢发现呢这种方式当然是创建了很多的压阻你也可以对你指定的压阻进行加效的技术但是呢我们希望能够去再管理一些更好的管理我们希望能够把这个压阻分成压庭去管分成这个压庭去管理最前很重要的一个希望能够对这个这个压庭然后呢还有这个一部分家庭等等去分开的进行这个管理还有呢去分开的这个 type of分开的时候对它进行压叫那这个时候这个怎么说用哪个模式去所以呢我们现在刚才这个就是十个问题的描述这种清晰所以呢我们现在要进一步的描述它的问题这个还是问题的描述问题描述是什么呢我们希望能够对collections of thoughtsand even some collections of thoughts
去进行管理也是我们可以把压庭分成一个一个collections一个collections上同时呢这个有一个除了这个之外我们又有一个新的什么效果描述我们不仅希望能够让它按照这个一个一个群体去描述它同时呢我们还希望这个群体呢是能够有真实的有collection同时呢我们还希望能够在一个群体上统一的使用统一的应用这三个条件结合在一起只有一个pattern和这个效果是哪个pattern啊只有一个因为从结构上我们把它分组并且呢左右分成此组这个是组合模式的结构性要求我们就功能性要求上组合模式要求能够在某一个组上统一的进行操作所以两点都完全符合的只有组合模式所以我们就可以用组合模式来完成这个任务那么组合模式来完成这个任务又是一样的大家又要想了组合模式中间实际上
只有一个勾向结构是重要的为什么呢因为这个除了结构就差一个而且呢在组合模式的结构中间注意一下confdict必然是一个额外添加的结构肯定在原来的设计中是没有的 因为你不用组合模式没有confdict是有的所以confdict也是额外添加的所以只要确定confdict是谁就可以了confdict是谁呢其实很简单这个confdict大家注意一下它是额外添加的它的这个add、reduce、get a child的操作也都是额外添加的它需要的confdict的节点上真正需要的一个只有它operation而这个operation是从内部的operation上拿出来实际上其他三个都是不太重要也是额外添加的只有这个operation是断线在我们的例子中这个operation是谁啊
就是pack所以这个component的例子是back这个component是谁啊所以在这个体现一旦你确定了component是pack那例子back、confdict是额外添加的比如说叫压群、flock就好了所以你只要新添加一个类就好了因为这三个类中间这三个角色中间这个已经有了这个已经有了你只要添加一个类我们把它命名成flock、压群所以你只需要添加一个castflock、back然后添加add方法、reduce方法这个不写了给它try的方法然后添加一个quack方法这个quack方法能够在一个压数集上进行操作操作方式也很简单用一个reduce就好了好那当然有同学说reducer怎么来那这样一来这个问题又解决了但是大家要注意一下可能会有同学讲这个问题
就是说在我们这里中间我们的这个大家会说你这样实现的话component有operation, add, remove, get, charcomplete也有operation, add, remove, charleaf也有这个operation这个是我们这个组合模式的要求对不对组合模式的要求现在按照我们刚才的实现跟这个图有什么不一样的地方我们刚才的实现跟这个图是不是不太一样对吧不太一样在哪里在于这个地方我们的component只有operation因为我们的component是quackable里面只有一个方法你没有办法再添加allery, remove, get, char因为这个quackable已经前面定义设计好了那这个行不行
这个事情呢这个是我们的Cinque inverses and char这个在前面讲组合模式的时候也讲过了就是安全的组合模式和透明的组合模式安全的组合模式是什么component是一个完整的接口拥有所有的操作而透明的组合模式呢component of Perquè安全的组合模式我们一般讲的是透明的组合模式,就这个,透明的组合模式。
Component拥有所有的接口,所以用户在访问节点的时候,不需要区分粒组和completes。
而安定的组合模式呢,Component只有一个接口。
用户在访问对象的时候,要把它转成completes类型,才能访问到他的Admin组合模式。
那么,但是这是一种选择,我们两边词上都讲了,我就不展开了。
就是你如果要tranquility,你就必然当成safety,也就要做异常处理。
你如果要safety,你必然要打半实体类型,你就失去这个透明性。
这个就是角色上的平衡,你必然不可能两者兼得。
那么在我们这个例子中间,因此呢,我们按照原有的设计,尽可能改动小的前提,假如是用这个item的组合模式,这样的话呢,试试也就完了。
好,现在呢,这个completes is ready,我们就可以用这个completes模式。
现在呢,completes is working great,我们现在呢,希望有一个相反的request,因为有一个新的request。
我们现在也also need to track individual docs。
我们刚才都是要么对整个鸭群应用进行,要么是对一个鸭群应用进行,完了。
我们现在呢,希望能够track individual docs。
那什么是track individual docs呢,这个描述不清楚。
我们这个时候加了一个描述考虑,我们希望能够track individual docs in real time。
我们希望能够获得单个鸭子的鸭叫,一旦单个鸭子的鸭叫了,我们就能收到这个消息。
这个时候我们应该用的一个模式啊。
这个时候这个描述其实很明确。
我们希望是什么,什么叫track individual docs?
就是不确定的个体,对吧?
它没说是哪个,我们希望一些不确定的个体能够实时地获取它们的状态。
因为鸭叫实际上就是状态变化,对吧?
我们能够实时获得不确定个体的状态变化。
这个时候你选择什么?观察者。
只有观察者符合这个鸭子。
观察者里边就有一条,首先它的约示它的realtime模式。
所以你看到realtime没有在下边,是不可能,但是不一定就是。
也有可能是其他的模式,但是起码它是符合鸭子。
现在加上一个小组,因为这个是大组,它是一些个体鸭子,但是没有指定一个具体鸭子。
所以非确定个体的鸭子观察通讯就是观察者。
所以这个时候我们就可以使用观察者模式来解决这个问题。
那么一旦有了观察者模式之后,我们又有新的难题了。
刚才也提到过观察者模式实际上是一个比较难的。
观察者模式是一个很常见的联合使用的模式。
很常见的联合使用的原因是因为观察者模式,前面讲过了,它的观察功能是和类对象的主要功能正交的一个模式。
所以它非常容易联合使用,你不会影响它原有的功能。
但是呢,另外一方面,因为它是一个正交的模式,所以它要添加额外的接口。
所以这就造成使用比较困难,需要改动比较大。
那这个时候我们怎么做呢?我们要确定这个接口。
那这个接口的时候大家看,首先这一部分实际上你是不太要关注在我们的例子中间。
因为我们的例子中间,你现在要去观察鸭架行为的Petrologist,它还没有在我们的设计中出现过,还没有出现过。
因为原来我们的Count就是值,它可以独具的话。
现在呢,当然你既然要去用观察者模式实际上,你必然要把这个通知到对象。
所以呢,我们的观察者对象是Observer,实际上是需要你去考虑。
还没有出现过,你可以去外添加新的类,做Petrologist。
关键就是这个鸭子类。
这个鸭子类呢,大家可以看到它一旦有一个变化,我们怎么去扩展它的Support。
我们采取一个最当前改变,最小的方式提供。
首先呢,Observer,我们有一个新建一个Observer接口,我们叫做CapObservable。
然后呢,接下来我们要求所有的这些具体类都能够变成是一个CapObservable。
注意啊,这个Observable是这个,这个其实只是起名啊,Java中的起名方式。
Java中间的Observable是什么?是Subject。
Observable是被观察的,可能被观察的。
所以Observable就是Subject,Observer才是观察者。
Observable就是Subject。
所以我们现在讲的是Observable,就是这个被观察的鸭子要对象。
那这个时候呢,我们怎么让这个鸭子变成,能够提升这个Observable呢?
我们不改变这个鸭子类,我们做一个最小的改变。
我们的接口可以实现另一个接口。
所以呢,我们让这个Quackable去什么?
让这个Quackable去实现这个Quackable的动作。
这个改动是必须有,你总是要让这个,我们的这个,刚才讲的这个新添加的Subject必须改动。
你要添加Subject,你必须改动原来的单。
这个是没有办法的。
那么,但是呢,改动的时候你可以选择两种。
你可以让这些鸭子类去实现一个额外的Subject,也就是Observable。
但这个时候你需要改变很多的类。
那么简单的方式就是你让Quackable去实现Observable,同时不改变其他的内容。
那么Quackable改变了这个Observable之后呢,它的这些这个Register等等,这些都可以在这个实现,都可以实现。
那么Observable呢也是一样,反正我们几个外形加Observable。
QuackableLogic可以实现Observable,这个比较简单。
好,这样就实现完了。
好,那现在呢,我们现在有这个我忘了一个讯程,反正这个有个六个讯程完了之后,接下来呢我们就实现了这样的一个类子。
大家可以看到,在这个类图中间,这部分其实比较简单。
这个呢就是Aftere,这个是两个方向,两个部分,这左边就是右边,这将是左边和右边。
为什么能够看看这两部分呢?
这边也不重要,这边就是抽象鸭子工厂,就是鸭子工厂,就是Counting Yard。
这边呢就是Observable和QuackLogic,Observable和这个鸭架之间。
所以这部分内容都是额外性加的一些功能,反正差别也不复杂。
所以这五个类我们可以估计。
主要呢就看这些类,这几个类其实也没啥,就是Mirror Dark, Redhead Dark,这个鸭子。
所以真正有用的就是1,2,3,4,5,6。
这六个类。
这六个类呢,上面有Observable,然后呢它继承,这边有QuackLogic,这个QuackLogic非常重要。
它既是Director,它比较硬的类子,也是Computed组合模式的Component,同时呢也是Decorator的Component,同时呢它继承是QuackLogic。
所以它是把这个什么工厂,同时它有本面的携带,Apple携带。
所以它是工厂的Apple携带,是Decorate,是Adapter的Target Interface,是Computed的Component,是Decorate的Component,同时也是Observer,Observer里边的Observer不太清楚的词类。
所以虽然我们这里边一共用了几个模式啊,工厂模式一个,对吧?
然后呢这QuackLogic模式两个,Adapter三个,素的五个,虽然我们这里用了五个设定模式,但是你画一个类图,实际上它就很少。
如果淘去这几个类,Adapter3,4,5,6,7,8,9,10,11,一共也就是11个框框,你就会有这个各模式严格使用,而不是说大和弱,实际上它们就是叠加在一起,叠加在一起。
那这里呢,其实还有一个小巧思啊,这个大家注意一下,这里有五格不合类,这个是什么?
这是观察的模式的一个派生扩展,这个是外部观察的对象,也就是这个主题的功能,是由一个外部对象,实现的。
这个接口呢,只调用这个外部对象的实现,做到了这个什么,改动对象,都是通过添加额外的类比实现。
我们这里唯一的一个改动,只是让这个重写了一下QuackLogic,让它implement这个QuackLogic,其他其实都没有,对原来的设定做改动,都是通过添加新的类比,来实现,对不对?
所以对模式的扩展,大家也要熟练地使用,这个外部观察者模式对象,是最常用的一个扩展,它避免了对这个抽象类,避免了使用抽象类的方式,对吧?
你不必须要使用抽象类,但是同时又能复用这个实现,复用这个主题的QuackLogic的实现,这个在我们讲方向表模式的时候,应该也讲过这个扩展。
好,那么,这个,到此为止呢,我们的这个五十一课就讲完了,这个,我们就看到这个,最后一个这个设计,大家要关注,整个把这个流通给大家讲,你就是要,我先看出问题,这个问题呢,一定要把这个,约束和效果,在确定了这个模式之后呢,不是简单的画这些模式,而且一定要考虑一下,这个模式的这个,之间有没有,角色的重叠,哪些角色是可重叠的呢?
最主要的是判断,抽象接口的重叠,因为一旦抽象接口重叠的时候,出来它的派生出来的实际对象,所以,这个是大家做这个设计的时候,最需要这个掌握的功能。
那么,大致上我觉得,今天的课题已经很到了,我计认为,你们把这个,比较好的,不管是形式也好,类型也好,主要的点,都是你们讲过的,就是多少这个形式,好,我们这个,这学期的,我要上的部分呢,就全部上完了,实际上,我跟大家上的本科课程呢,也就全部结束了,因为我其实,本科就上两本大单的课,然后,如果以后,还有缘的话,也许你们也会在我这边做B社,做B社的读研了之后呢,也许,某天你在这个江湖成功之后,我也会记得,来看看老师们就更好了,那我们这个,科就上到这边,如果大家有问题的话,我会带到这个加课,如果大家有问题,