迭代器模式个人总结:
定义:顺序访问聚合对象元素,无需暴露内部表示。
角色组成:
- 抽象具体迭代器角色(Iterator):定义访问和遍历元素的接口,记录当前位置
- 抽象具体聚合角色(Concrete Aggregate):获得迭代器角色。
场景或者优点:
- 访问聚合对象的内容无需暴露内部表示。
- 支持对聚合对象的多种遍历。
- 为不同的聚合结构提供统一的接口。
缺陷:
- 遍历的同时更改迭代器所在的集合结构会导致出现异常。
应用:C#中IEnumerator接口扮迭代器,IEnumberable接口则扮演聚集,有GetEnumerator()方法。
JAVA总结:
聚集和JAVA聚集:多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。数组就是最基本的聚集
JAVA聚集对象是实现了共同的java.util.Collection接口的对象,从1.2版开始,提供了很多种聚集,包括Vector、ArrayList、HashSet、HashMap、Hashtable等。
宽接口:聚集的接口提供修改聚集元素的方法。
白箱聚集:聚集对象为所有对象提供宽接口
游标迭代子:迭代子从外部控制聚集元素迭代过程。
外禀迭代子:迭代子是在聚集结构之外
意义: 1 支持对聚集对象的多种遍历。2 为不同的聚集结构提供统一的接口。
窄接口:聚集的接口没有提供修改元素的方法
黑箱聚集:为迭代子对象提供宽接口,为其他对象提供窄接口
黑箱实现方案:实现双重接口将迭代子类设计成聚集类的内部成员类
内禀迭代子(Intrinsic Iterator):迭代子是在聚集的结构之内定义
黑箱效果:迭代子可以访问聚集的元素,外界不能访问。
主动(外部)迭代子:客户端控制迭代元素,调用迭代子的next()等迭代方法。
被动(内部)迭代子:迭代子控制迭代元素。客户端需要传入操作,迭代元素时执行,类似回调。
静态迭代子:聚集对象创建快照。客户端修改原聚集内容,迭代子对象不会反映新变化。
静态迭代子的好处是安全和简易,短处是对时间和内存的消耗。
动态迭代子:创建迭代子,保持着对聚集元素的引用,修改原聚集会在迭代子对象上反映。
Fail Fast:算法开始之后,运算环境发生变化,使得无法进行必需的调整时,发出故障信号。
Fail Fast在JAVA聚集中的使用:JAVA语言以接口java.util.Iterator支持迭代子模式,Collection接口要求提供iterator()方法,此方法在调用时返还一个Iterator类型的对象。而作为Collection接口的子类型,AbstractList类的内部成员类Itr便是实现Iterator接口的类。
Itr类的方法checkForComodification()会检查聚集的内容是否刚刚被外界直接修改过(不是通过迭代子提供的方法修改的)。如果在迭代开始后,聚集的内容被外界绕过迭代子对象而直接修改的话,这个方法会立即抛出ConcurrentModificationException()异常。
优点:(1)简化接口。迭代子具备遍历接口,聚集不必具备遍历接口。(2)聚集对象可以有几个迭代在进行。
(3)支持对聚集对象的多种遍历
观察者模式个人总结:
定义:定义一对多的依赖关系,观察者监听主题对象,主题状态变化通知观察者更新行为。
角色:
- 抽象具体主题角色(Subject):持有观察者列表,提供增加和删除。状态改变时给观察者通知。
- 抽象具体观察者角色(Observer):得到主题通知更新自己
使用委托与事件可以简化观察者模式实现
适用场景:
- 一方面依赖另一方面,封装在独立的对象能独立改变和复用。
- 对象的改变需要改变其他对象,不知道多少对象待改变。
- 对象必须通知其他对象,不知道对象是谁。
优点: 1 实现表示层和逻辑层的分离,使得可以有不同的表示层(观察者)。
2 建立抽象的耦合,主体不知道具体的观察者,只是保存抽象列表。3 支持广播通信。会向所有观察者发出通知。
缺点: 1 通知所有观察者花费时间。 2 没有相应的机制使观察者知道怎样发生变化。
3 观察者有循环依赖,触发循环调用,导致系统崩溃。
Java总结:
是行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
推模型:主题向观察者推送信息,不管观察者是否需要,推送全部或部分数据。
拉模型:主题传递少量信息。观察者需要更多信息,主动到主题获取,相当于拉数据。一般实现把主题对象自传递。
推模型是假定主题知道观察者需要数据;而拉模型是主题对象不知道观察者需要数据。
推模型可能使得观察者难以复用。而拉模型不会造成这样的情况,传递主题对象本身,是能传递的最大数据集合,适应各种情况。
JAVA语言的java.util库,提供Observable以及Observer接口,对观察者模式的支持。
中介者模式个人总结:
定义:定义中介对象封装对象交互关系。
适用场景:1 一组对象进行复杂的通信。2 封装多个类的行为,不想生成太多的子类。
优点: 1 简化对象关系 2 各个对象独立易于复用。 3多对多变成一对多
缺点: 1中介者承担较多的责任,出现问题,受到重大影响。
2 新增加同事类时,修改中介者类
java 中介终结
又叫调停者模式
角色:1 抽象和具体调停者角色:定义同事到调停者的接口。知晓所有同事,协调交互关系。
2 抽象和同事类角色:定义调停者到同事的接口。同事只知道调停者。需要与同事通信,与调停者通信。
状态者模式个人总结:
内部状态改变时自动改变其行为
角色:
- 环境类类:维护状态类。
- 抽象状态类:定义行为约定。
- 具体状态类:实现行为。根据状态改变行为
状态者模式的应用场景:1 条件表达式过于复杂时 2行为取决于它的状态,运行时刻根据状态改变行为
状态者模式的主要优点是: 1 状态判断逻辑每个状态类里面,简化判断逻辑。2新状态添加新类来扩展。
状态者模式的主要缺点是:如果状态过多,会有非常多的状态类
JAVA总结:
状态和行为
状态,通常是属性;行为指的功能,具体是方法。
状态模式的功能是分离状态的行为,状态决定行为。行为在运行期根据状态的改变而改变。
行为的平行性:相互之间是不可替换的。
平等性是可替换性
环境和状态处理对象
环境是持有状态的对象,处理状态的委托给了状态类处理。
客户端只和环境交互。配置完毕,不需要和状态对交道了。
C#策略者模式个人总结:
定义:将不同算法封装到不同类,可以相互替换
角色:环境,抽象策略,具体策略
实现:环境持有抽象引用,抽象策略定义算法接口,具体策略实现算法
c#实现:LIst的排序功能,List<T>.Sort(IComparer<T>)
适用场景:1 动态选择算法 2 有大量行为,避免多重if
优缺点: 1 自由切换。2 易于扩展 3 避免多重条件选择语句
缺点:必须知道所有策略,自行决定使用哪一个。用ioc解决。
JAVA总结:
策略模式的重心:组织调度算法
算法的平等性:相同行为的不同实现
运行时策略的唯一性:一个时刻只能使用一个具体实现
公有的行为:公有行为在抽象类
责任链模式个人总结:
责任链模式,多个对象组成链子传递该请求,直到有对象处理它为止
角色:
- 抽象处理者角色(Handler):定义处理请求的接口。
- 具体处理者角色(ConcreteHandler):受到请求后,选择处理掉,或者传给下一个。
场景 1 审批需要多个对象 2存在多个if-else语句
优缺点 1降低了发送者和接收者耦合。2 把多个条件分散到各个处理类中。
缺点,如: 1 未在找到正确,所有的条件判定都要执行 2可能某个请求不被处理。
jAVA总结:
纯的责任链模式:处理者只能选择一个行为:一是承担责任 2 把责任推给下家
纯的责任链,请求必须被某个处理者接收;在不纯的责任链,请求可以不被对象接收。
Tomcat的Filter使用责任链模式,创建Filter要在web.xml做配置,还要实现javax.servlet.Filter接口。
Tomcat的容器设置也是责任链模式,从Engine到Host再到Context一直到Wrapper都是通过链传递请求。
ApplicationFilterChain类扮演抽象处理者,而具体处理者角色由各个Filter扮演。
Filter存放保存在ApplicationFilterChain类中的一个ApplicationFilterConfig对象的数组中。
当web应用首次启动ApplicationFilterConfig会自动实例化,从web.xml读取配置的Filter,然后装进该容器。
访问者C#个人总结:
封装的数据结构上的操作,操作和数据结构解耦。
角色:
- 抽象具体访问者:声明访问操作,接受节点对象参数。
- 抽象具体节点:声明接受操作,接受访问者对象参数。
- 结构对象:节点容器,包含多个不同类或接口的容器。
双重分派:节点调用访问者,将自己传入,访问者则将某算法针对此节点执行。
使用场景: 1 稳定的结构,变化的算法 2 一组类存在相似结构 3 一个对象存在不相干操作
优缺点:
1 添加操作容易,添加新类
2 有关操作集中到访问者对象
3 访问不同等级对象
缺点:
添加新元素类困难,要在访问者添加新操作。
java总结:
变量被声明时的类型叫做变量的静态类型(Static Type),明显类型(Apparent Type);
而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type)。
根据对象的类型而对方法进行的选择,就是分派(Dispatch)
静态分派(Static Dispatch)发生在编译时期,分派根据静态类型。比如方法重载就。
动态分派(Dynamic Dispatch)发生在运行时期,动态分派动态地置换掉某个方法。比如重写
方法所属的对象叫做方法的接收者,接收者与参数统称做方法的宗量。
单分派语言根据一个宗量的,多分派语言根据多个的宗量。
Java就是动态的单分派语言,考虑接收者的类型,又是静态的多分派语言,考虑类和参数
一个方法根据两个宗量的类型来决定执行不同的代码,这就是“双重分派”
在Java中可以通过两次方法调用来达到两次分派的目的。
动态单分派在Java语言中是在子类重写父类的方法时发生的。
C# 备忘录简单总结:
个人定义:对象之外保存它的内部状态,以便恢复
1 场景: 提供回滚:比如数据库事务
2 优缺点 1 恢复数据 2 备忘录保存备份 ,单一职责 3 缺点:维护多个备份消耗资源
- 发起人角色:创建和恢复备忘录数据。
- 备忘录角色:1 存储内部状态,恢复时提供状态。2保护内容不被发起人之外读取。
- 管理者(负责人)角色:1 保存备忘录对象。2不检查备忘录的内容。
JAVA总结:
又叫快照或Token模式,是行为模式。
两个接口: 1 窄接口:只允许把备忘录对象传给其他的对象。 2宽接口:允许读取所有的数据
备忘录角色对任何对象都提供宽接口,叫做“白箱实现”。
备忘录角色对发起人提供宽接口,其他对象提供窄接口。叫做“黑箱实现”。
在JAVA,实现双重接口的办法就是将备忘录角色类设计成发起人角色类的内部成员类。
在“自述历史”模式里面,发起人角色自己兼任负责人角色。