1.模板方法模式 Template Method
主要逻辑在父类中实现,子类只实现部分抽象方法或者钩子方法。
钩子方法的目的是让子类能够控制模板算法中可选的部分。
2.状态模式。
context中默认有一个当前状态。
如果有context请求都委托当前state执行,状态的切换可以再state中切换,也可以在context中切换,具体看是否需要动态切换。
每个状态子类只需要考虑一种情况,大大提高了可维护性,每个子类状态可以包含context,从而可以控制context状态的流转。
如果有情况新情况增加,只要添加一个state实现类即可,此处可能关联到某些状态跳转到新状态的可能性,只需要修改到需要关联的状态即可,不用修改所有的状态。如果是原来的的if else的话,可能每种情况都需要考虑了。所以此处体现了开闭原则。
命令模式主要用于将请求者和执行者解耦。
就拿餐厅来举个例子,如果客户Client点菜下单,这个menu就是一个commnd,这个commnd可以指定哪个厨师烧什么菜,如commnd1是厨师A烧牛排,commnd2是厨师A烧pizza和调制果汁,commnd3为厨师B烧牛排...
。客户点完菜单生成一个commnd,将commnd菜单通过setCommnd递交到服务员invoker,此时服务员invoker就具有了一个或者多个commnd。但是何时将菜单递交给厨房柜台的方法execute由服务员决定,服务员invoker可以决定有一个菜单就执行execute送菜单还是多个commnd才执行execute送菜单的服务。
命令模式的使用场景
1.队列请求,请求者将请求封装成commnd发送过来,这边开一个队列来存储源源不断的请求,再开一线程不断从队列里面拿请求。处理请求的方法很简单,不用知道具体的请求对象,和具体要做什么操作,只要执行commmnd.execute()方法即可。
2.日志请求,请求者将操作数据库的动作封装成commnd序列化到磁盘上。如果发生宕机,则从磁盘上反序列化到Invoker,Invoker不用注重具体操作的对象和具体的动作,只要执行execute就能恢复宕机后的数据。
4.迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不用暴露其内部的表示。
Aggregate聚合接口是主体,每种集合都一个具体Aggregeta实现类,同时包含一个iterator实现类。
使用流程从Client发起,Client先创建一个集合,通过集合可以获取Aggregate接口对象,通过Aggregate接口对象的createIterator()获取Iterator接口,通过Iterator接口来遍历对象。绕了一圈啊,但是不同的集合统一的API还是挺优美的。
5.策略模式
定义了算法族,分别封装起来,让它们之间可以互相替代,此模式让算法的变化独立于使用算法的客户。
这里讲述了部分OO原则:
封装变化,将变化的部分抽象出来,让以后能够更灵活的修改,软件设计之初就应该开始考虑,软件设计完成之后,变化的部分相对来说会更加的明显,更需要考虑封装变化。
多用组合,少用继承。继承的缺点即所有的子类都实现了相同的方法,冗余度会很高,继承的情况,通常只会将确定不会变化的东西封装在父类中,用于继承。
针对接口编程,不针对实现编程。此处讲的接口不纯粹是一般意义上的接口还包含了抽象类。针对接口编程这接口定义的内容可以动态扩展,提高了代码的弹性。
6.观察者模式
定义了对象之间一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都能收到通知并自动更新。
观察者模式实现了对象之间的松耦合,主题或者观察者只依赖事先定义好的接口,所以只要他们之间的接口仍然被遵守,我们就可以自由的改变他们。
我们简单分析下类图吧,subject也称为observerable可观察对象。
为何要添加setChanged()方法呢?这个方法主要控制变化频率吧,我们用于控制什么样的change是我们预期的change,什么样的change是可以忽略的,因为有时候可能不是希望所有的变化都通知观察者。
为何要提供getState方法呢?因为状态分为推拉两种,如果推的话obserable不知道具体的observer需要哪些状态,所以一般只能将所有的状态推送给observer
至于拉的话我个人理解则显的更为灵活,通知观察者让他们自己去拉状态,但是这样也有个问题,观察者必须要预先知道observerable内部的状态。
为何观察者内部需要保留observerable的引用?我认为主要涉及两点吧,第一个要拉上一个问题中的状态,第二解除观察者关系,虽然observerable中提供了方法主动权在observerable,但是observer中有了引用则更会更加灵活,observer可以方便的解除观察者关系。