《软件框架设计的艺术》读书笔记

Posted on February 26, 2012

从老大位置上淘来的好书《软件框架设计的艺术》,只看了几章。先写点读书笔记备忘。后续再更新。

书中大部分的内容,都是围绕框架向后兼容性,和可扩展性展开的。全书虽然是基于Java写的,但是对于AS来说绝大部分也同样适用。

一.只公开你需要公开的内容。必须要限制对外公开的方法和属性的数量,包括public 和protected的,这些API一旦公布,就代表了对外的一种承诺,你永远不能去改变他们。否则就会带来框架版本的兼容问题。只有框架内部使用的公开方法,也不应该对外公开,给上一个“此方法仅框架使用,外部不可以使用”这样的文档注释是很糟糕的。但是原生提供的internal修饰符又只支持包内访问。针对这个问题,书里还特别提供了一种在Java里能巧妙的跨包访问又能对外屏蔽的方法。讲解的有点复杂。不过这个在AS里是很容易的,可以通过自定义一个框架内部使用的命名空间作为新的修饰符就行了。具体可以参考Flex源码里随处可见的mx_internal。在这个命名空间下定义需要跨包访问,但又不想被用户调用的方法,属性和类。

二.避免深层次的继承。子类可以通过覆盖父类的方法来改变父类行为。但继承的重点不是用来改变行为的,而是扩展功能的作用。子类跟父类应的关系该是跟描述自然世界里的关系一样。子类屏蔽掉自己额外的功能后就一定可以完全被当做父类来使用。如果只是为了复用父类的部分代码,应该使用接口。

三.模块化架构一章中强调了框架内部分模块解耦的重要性,这要求不模块的代码互相之间不能引用。但是互相引用的情况,是必然发生的。对此,书中提出了用“依赖注入”的方式来统一解决这个问题的方案。依赖注入简单的说也就是将所有需要直接用其他模块类的地方,都定义上接口。把使用对应的类,改为使用接口。而对应的类都去实现这个接口。最终使用一个配置类,配置每个接口默认的实现类,从而把所有依赖关系都转移到这个一个配置类里面而不是分散各处。所有依赖的地方,都使用这个配置类来查询自己使用到的接口的默认实现类。本质上还是依赖的,引用也没有断开,只是挪了个位置,都放在配置文件里了。一旦模块发生变化,改变一个配置文件比改变意大利面条式的交叉引用更有效。

最后依赖注入的重点就都转移到了这个配置文件上,书中讨论了多种管理这个配置文件的方案。最基本的一种是,直接使用一个类,里面用代码一一写好相应接口到默认实现类的映射关系供查询。但是这个不太方便管理。所以有了进化的方案。也就是著名的Spring框架里的注入机制。用外部xml来配置这些映射关系,运行时载入解析成一个查询类。实际上原理还是跟第一种差不多。只是把用代码方式的配置改成xml,对于不了解框架的配置人员来说,比较方便而已。我试着想在自己的框架里应用这种依赖注入机制,把模块解耦。典型的应用就是所有的UI组件都有一个默认的皮肤类。但是遇到一些问题:

1.在无需人工干预的情况下,框架内部代码实现依赖注入:如果我用第一种方式,将所有映射关系都定义在一个LookUp类里,而所有组件都通过这个类查询默认皮肤,这样编译的时候,我只要使用了一个组件,就会导致,所有的默认皮肤都被编译进最终代码里。这个感觉是很糟糕的。如果我用第二种,用字符串的方式获取类定义的话,是绕过了编译器。但是对应的类可能根本不会被编译进代码。导致获取不到定义。所以第二种方案也只能把所有类都默认强制编译进代码才能实现。

2.在项目阶段配置依赖注入。这种方式就不存在上面的问题了,可以只配置具体项目用到的类,才编译进代码。不会有冗余。但是问题是,为此每个项目都要单独写个自己的配置文件。这个有点太麻烦了。不够智能。

3.在编译器阶段配置依赖注入。淘汰了前两种方案后,我突然发觉Flex里也使用了依赖注入,而且用的非常巧妙。但它框架内的组件就不存在一处引用默认皮肤的地方,同样也不需要用户自己写项目配置文件。那它是在什么时候配置的默认皮肤呢?最后我试着用mxmlc编译了一个mxml文件后再查看它自动生成的代码,终于找到了默认皮肤的配置。编译器对项目中使用的组件自动添加上了对应默认皮肤引用。原来Flex是在编译器里做了手脚啊。