《敏捷软件开发》读书笔记(3)

倾然丶 夕夏残阳落幕 提交于 2020-01-11 04:04:07

《敏捷软件开发》读书笔记(3)

书中设计模式的汇总

命令类模式,分离执行和定义

CMD模式

其实是事件-事务绑定的模型:

  1. 可以用事件驱动,只要收到事件,执行绑定到事件对应的CMD对象.do方法就行,对于真正执行的事情无感知。解除了系统的逻辑互联关系和实际连接关系的设备之间的耦合。
  2. 事务型操作,把验证和执行分离,由执行框架完成验证和执行操作。解除了获取数据、验证数据、执行数据操作这种空间耦合,同时也可以在执行时间上进行解耦。扩展可以增加undo接口,系统把CMD对象压入堆栈,在进行回退的时候调用undo。

整体上就是把程序算法或者业务逻辑,和程序的实际控制执行解耦,有点像函数式编程。

ACTIVE OBJECT模式

这部分没看懂,似乎是多线程任务执行引擎,可以把CMD对象放回到引擎列表中。这种类型的线程任务是RTC线程。

复用算法,分离业务逻辑的模式

TEMPLATE METHOD模式

把算法的控制和逻辑分离,通用算法封装到基类,不需要理解的逻辑部分交给子类实现,比如冒泡排序。(其实不一定用继承,可以用组合),注意防止滥用。

STRATEGY模式

相比TEMPLATE METHOD,更好的解除了具体实现和算法的耦合,使用接口+组合,而不是继承,能提高具体实现的复用性,优先使用。

统一对外接口,隐藏策略的模式

FACADE模式

封装组件对外的策略和约束,要求外部系统统一通过某个简单且特定的接口访问,对外呈现唯一的代理接口。

MEDIATOR模式

也是策略的一种,但是是隐蔽的,比如监听文本变化并且对其他列表进行操作,文本框本身是不感知到策略的存在的。

单例的两种模式

SINGLETON模式

单例对象,是非常常用的模式,好处:跨平台、适用于任何类、可以派生创建、延迟求值。代价:无法指定销毁机制、不能继承、效率问题、不透明性。强调结构上的单一。

MONOSTATE模式

对使用者而言是多个实例,但是内部操作的是同一个空间。好处:透明、可派生、多态。代价:不可转换、效率、内存、平台局限。强调行为上的单一。如果希望对使用者透明,或者希望用单一对象的多态对象,比如状态机,可以选用。

NULL模式,避免判空编码

NULL OBJECT模式

用空实现代替返回null指针,避免判空的同时,也明确了对象不存在时的行为。

FACTORY模式

使用这个模式,可以满足DIP原则,避免依赖实现类,不要直接new,可以用Factory来完成创建。但是这会让调用方对工厂类产生依赖,一旦创建类型增加,就会被迫重新编译部署,可以用字符串映射的方式牺牲一点类型安全性。好处是可以无缝替换实现,让调用者依赖抽象。可以解决包之间耦合具体实现的问题。

COMPOSITE模式

如果对一组对象的使用行为完全一致,那么可以创建一个包含该对象列表的对象,让客户方还是认为是一对一的结构关系,把行为变成一对多的。要注意只有使用对象是完全一致的方式才具备转换的可能性。

OBSERVER模式

又是个常用的模式了,可以满足设计的OCP原则。这里得到新的理解是分为“推”模式和“拉”模式。推即为数据更新的时候,主动把数据推送给观察者,拉即为数据更新的时候,只发送更新通知,让观察者主动去查。拉模式的关键问题在于,不知道数据源发生了什么样的变更,不过观察者模型的对象简单,复用程度高。对于如何选择,如果被观察的对象简单,适合用拉模式,如果很复杂,可以用推模式,告诉观察者什么发生了变化。

几种桥接解耦的模式

ABSTRACT SERVER模式

解决使用方依赖具体实现方实现类的问题。客户调用提供服务方,如果要避免依赖具体实现,满足DIP原则,那么可以定一个接口,由客户方调用接口,服务方实现接口。而且接口是属于客户方定义的。

ADAPTER模式

如果以上的ABSTRACT SERVER模式,服务方无法实现接口或者是第三方的,那就在中间加一个ADAPTER实现接口,再调用真正的服务方。(以上是对象形式的,还有一种类形式的ADAPTER,没太理解)考虑书中282页的调制解调器的例子,可以用ADAPTER隔离真正客户方不关心的部分,在ADAPTER里处理对接已有系统的兼容转换逻辑。

BRIDGE模式

略显复杂,在遇到类层次自由度多的时候,可以把结构分开,用桥结合到一起。不会影响到使用方,而且把不同实现策略的服务方隔离开了,最终还是解决隔离的问题,还需要再理解一下。

故障隔离相关的模式

以下模式是为了解决软件中处理故障的同时,任然保持程序关注于本身要解决的问题,不过要注意不要在一开始就预测需要的模式,建议先用Facade模式,再在必要时重构。

PROXY模式

需要用到数据库的地方,让数据库操作的类,实现领域接口类一模一样的方法,作为Proxy类,然后数据库实现类去依赖领域实现类,完成数据库到实体的转换,再完成接口调用。这样把业务逻辑保持封装在领域模型中,任何数据库的更改,不会影响到领域模型。(不明白的点是,调用方要直接创建数据库的代理实现类,修改的时候其实是会影响调用者的吧?另外,代理如何做到第三方的依赖反转的?)注意代理是非常重型的模式,需要谨慎使用。

STAIRWAY TO HEAVEN模式

和上面的PROXY类似,但不是用委托调用领域类,而是用继承实现,这对语言有要求,需要支持多重继承。

可以用于数据库的其他模式

EXTENSION OBJECT模式

由领域类直接返回扩展对象如Database扩展,然后直接调用扩展对象进行数据库读写。

VISTOR模式

把写入动作交给Vistor,由具体对象的accept方法执行结构化写入(Android的序列化就是这样的模式)

Decorator

装饰一个业务对象并赋予read和write方法;或者可以装饰一个知道如何读写自身的数据对象并赋予业务规则

Facade

直接对外提供readXxx/writeXxx方法,会有些耦合。

解决类层次的扩展问题的模式VISITOR

解决的问题:需要向类层次结构中增加新的方法,但是增加起来会很费劲或者会破坏设计

VISITOR模式

增加一个访问者的角色,用visit的方式去调用被访问者相关的方法,可以满足开闭原则,对现有系统影响最小。核心是双重分发,第一次是accept方法的多态分发,分发到要执行方法所属的类型,第二次是visit的分发,分发到要执行的具体函数或者逻辑。对于被访问者每一个实现类,访问者都有一个对应的方法,被访问者在accept里调用访问者.visit(this)。书中利用Model的例子,解释了如何构建VISITOR模式。如同一个功能矩阵,每个点都由对应的实现。但是这里有个问题,visitor依赖实现类,但是被访问者依赖这个访问者,会存在循环依赖。

ACYCLIC VISITOR模式

为了解决以上循环依赖的问题,可以将visitor变成退化的,耦合具体访问者实现的部分,提供一个接口出来给访问者调用,完成派生类到接口的180度旋转。但这样的方式更复杂,而且转型耗时无法估计,对强实时系统不适用,对增量编译比较重要的系统适用。这个模式如同一个稀疏矩阵,可以裁剪某些不必要的功能。

VISITOR模式还可以用于生成报表,而不打破任何数据的数据结构。通常在程序中存在许多种不同方式进行解释或者使用多数据结构时,就可以使用。可以让每个访问者所使用的数据结构都独立于他的用途,并且访问者还可以随时创建新的,可以随意配置部署,这太棒了。

DECORATOR装饰器模式

再次考虑Model的情况,如何在不修改已有类行为的情况下,增加拨号时的处理?解决方案是创建一个新的装饰类实现Model接口,并且传入已有的Model对象,在dial方法之前之后进行其他处理,将真正的拨号委托给原Model对象,完成了功能的增强又不修改原代码,这也体现了面向接口编程的好处。如果有很多装饰类,可以创建一个基础装饰类,把通用的委托代码放在里面,由具体的装饰类继承实现,复写需要委托的方法部分即可。

EXTENSION OBJECT模式

类层次中每一层根据一个KEY来管理扩展对象,由扩展对象进行扩展功能补充,比如序列化为XML或者CSV扩展。并且扩展对象可以在创建时进行指定,或者动态添加删除。

总结:以上三种模式,有助于保持OCP,在不修改原有代码的情况下增加行为和能力,也增强了SRP原则。

STATE设计模式

有限状态自动机,至少由4部分组成:起始状态、触发迁移的事件、终止状态、要执行的动作。可以借助以下两种表达方式,这两种表示方式,可以帮助我们分析场景不要遗漏,比如每个状态遇到每种事件多时候,分别应该做什么样的处理。:

STD状态迁移图

[起始状态]->触发事件/执行动作–>[终止状态]

STT状态迁移表

起始状态 触发事件 终止状态 执行动作

如何实现STATE模式

嵌套switch/case语句

处理每个状态下,收到每种事件后,相应的处理。另外,action的抽象,使得状态机的逻辑和执行的具体操作实现之间解耦。这种方式的好处,对于简单的状态机实现很清晰,但是对于大型的FSM来说就会是噩梦。另外一个代价是,逻辑和实现代码不容易被很好的分离。

解释迁移表

创建一个状态迁移表,由一个迁移引擎来进行事件匹配迁移和调用相应动作,修改状态。这种好处是,构建迁移表的代码读起来就像是一个规范的迁移表,状态机的逻辑全部集中在一个地方,并且不会被污染。另一个好处是迁移表可以动态部署,实现业务逻辑的热补丁。代价主要是速度,解释迁移表需要时间,而且解释引擎会比较复杂。

STATE模式的结构实现
  1. 定义一个State类,提供的接口是迁移事件。
  2. 由具体的State实现类处理每个迁移事件,调用上下文类的动作和状态迁移方法。
  3. STATE模式是一种STRATEGY的一种特例,派生类会回指上下文类。

用这种实现彻底分离了状态机的逻辑和动作,而且可以轻易扩展状态、修改动作的实现,且非常高效。代价主要是编写状态派生类会比较麻木,另外逻辑是分散的,无法在一个文件里就看清整个逻辑。

SMC 状态机编译器

作者利用工具,设计了一个描述问题,把FSM的描述文件,自动生成一组实现状态机的类。

可以在哪些地方使用状态机

GUI中的高层策略

比如登录界面的业务逻辑,可以用状态机来表达(回想项目中,初始化路由过程也可以通过状态机表达)

GUI交互控制器

GUI上的实现,接收用户输入事件作为状态迁移事件,驱动屏幕绘制相关的动作执行和状态迁移。

分布式处理

比如TCP数据传输的端口状态。

总结:FSM没有被充分使用,在许多情况中,使用FSM会有助于创建更清楚、简单、灵活以及准确多代码。(即使不用状态机实现,用状态机分析思路也有助于做出可靠的程序)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!