《程序员修炼之道》读书笔记(5):弯曲,或折断(更灵活的代码)

第5章:弯曲,或折断

我们需要让自己的代码在面对不确定的世界时保持灵活性可适应性

以下是方法:

  • 解耦。让分离的概念保持分离,降低模块间的耦合程度。
  • 将一些细节移出代码。
  • 减少时间上的耦合。
  • 将模型与视图分离。
  • 一种解耦的技术:提供一个“聚会地点”,各模块可以在那里匿名和异步地交换数据。

26《解耦与得墨忒耳法则》

在《正交性》和《按合约设计》中我们提出,应该编写“羞怯”的代码,其工作方式有两种:

  • 不向别人暴露你自己
  • 不与太多人打交道

让模块相互了解有什么问题?
原则上没有。
但是过多的直接依赖关系会造成组合爆炸。可以通过若干方式看到这一现象的症状:

  • 这样的C/C++大型项目:用于链接某个单元测试的命令比测试程序自身还要长。
  • 对某个模块的“简单”改动会传遍系统中的一些无关模块。
  • 开发者害怕改动代码,因为他们不清楚哪些代码可能会受影响。

通过编写尽可能遵守得墨忒耳法则的“羞怯”代码,我们可以实现我们的目标:
——使模块之间的耦合减至最少。

——来自维基百科:
得墨忒耳定律Law of Demeter,缩写LoD)亦被称作“最少知识原则(Principle of Least Knowledge)”,是一种软件开发的设计指导原则,特别是面向对象的程序设计。得墨忒耳定律是松耦合的一种具体案例。该原则是美国东北大学在1987年末在发明的,可以简单地以下面任一种方式总结:

  • 每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元;
  • 每个单元只能和它的朋友交谈:不能和陌生单元交谈;
  • 只和自己直接的朋友交谈。

这个原理的名称来源于希腊神话中的农业女神,孤独的得墨忒耳
很多面向对象程序设计语言用.表示对象的域的解析算符,因此得墨忒耳定律可以简单地陈述为“只使用一个.算符”。因此,a.b.Method()违反了此定律,而a.Method()不违反此定律。一个简单例子是,人可以命令一条狗行走(walk),但是不应该直接指挥狗的腿行走,应该由狗去指挥控制它的腿如何行走。

使用得墨忒耳法则将使你的代码适应性更好、更健壮。
但是也有代价:你需要大量的包装方法。

与任何技术一样,你必须平衡正面因素和负面因素。

27《元程序设计》

“细节”会弄乱整洁的代码,特别是他们经常变化的情况下。
因此需要把“细节”赶出代码。可以通过“元数据”。

元数据到底是什么?
严格来说,它们是关于数据的数据。

最基本的用法是作为配置。

更高级的用法是驱动应用——将抽象放进代码,将细节放进元数据。
这样有若干好处:

  • 它迫使你解除设计上的耦合,从而带来更灵活的、适应性更好的程序。
  • 它迫使你推迟细节处理,创建更健壮、更抽象的设计。
  • 无需重新编译,就可以对其定制。
  • 与通用的编程语言相比,可以通过一种更为接近问题领域的方法表示元数据(见《领域语言》)
  • 甚至可以用相同的引擎,不同的元数据,来实现不同的项目。

此时的行为类似于《领域语言》中讨论的实现一个小型语言。

28《时间耦合》

时间是软件架构常常被忽视的方面。但它有两方面很重要:

  • 并发(事情在同一时间发生)
  • 次序(事情在时间中的相对位置)

当我们在思考架构或编写代码时,思维往往是线性的,例如:先做这个,再做那个
而这样就会带来耦合——时间上的耦合。

我们需要尽量解除时间上的耦合,这样做可以获得更好的灵活性:

  • 首先,分析工作流,思考改善其中的并发性。
  • 当以并发性进行思考时,有时会让你对架构有更好的理解,使你更易于编写它。
  • 设计代码时要时刻考虑并发性,这样也会设计出更好的接口
  • 一旦你有一个考虑并发的架构,并在所有设计中都考虑了并发,那么你可以更灵活地进行部署:客户-服务器、或是层、或者单机——即选择不并发。

29《它只是视图》(将视图与模型分离)

一旦你基于责任将程序划分为不同的模块,你就有了新的问题:在运行时它们怎么交流?
你应该让它们的耦合最小——事件发送者不需要对接收者有任何明确的了解。

可以使用 分布/订阅 的设计,参见设计模式中的 观察者模式

Model-View-Controller是惯用手法。
在这之后的关键概念是:让模型与表示模型的GUI分离,也让模型与管理视图的控制器分离(视图与控制器可能耦合,在某些MVC实现中二者是一个)。

但是MVC并不必须要有GUI。

  • 模型。表示目标对象的抽象数据模型
  • 视图。解释模型的方式。
  • 控制器。控制视图,并向模型提供数据的途径。

最后,尽管这些都能减少耦合,但是耦合依然存在。
下节是进一步减少耦合的一种途径。

30《黑板》(共享空间)

想象警探判案:
他们在面前放一个大黑板,然后不断地写下问题、补充资料,最后可能会发现某些关联,然后做出假设。这样的过程将会持续进行,跨过所有班次,直到案件了结。
黑板的一些关键特性是:

  • 没有侦探需要知道其他侦探的存在——他们只需盯着黑板。
  • 侦探可能接受不同的训练、有不同的教育背景、不同的专业经验。但他们都渴望破案,这就是全部共同点。
  • 在这个过程中,不同的侦探可能会走来走去,工作班次也可能不同。
  • 对放在黑板上的内容没有什么限制。可能是图片、判断、物证、等。

黑板系统完全解除了对象之间的耦合,所有对象在其中匿名、异步地交换数据,也减少了代码数量。

你可能需要对你的黑板进行组织。

JavaSpaces是一种实现,可进行的操作只有四种:

  • read:在空间中查找并获取数据
  • write:把数据项放入空间
  • take:与read类似,但同时从空间中移除该数据项
  • notify:设定每当写入与模板匹配地对象时就发出通知

这样系统的一大优点是:单一而一致的接口。
对比传统的方法,你可能需要精心制作很多独特的API,随着接口和交互的组合爆炸,项目很快就会变成噩梦。

猜你喜欢

转载自blog.csdn.net/u013412391/article/details/115164255