关键的设计概念摘要

管理复杂度

  • 软件首要的技术使命就是管理复杂度。
  • 我们不应该同时把整个程序塞进大脑里,而应该试着以某种方式组织程序,使得我们在某一时刻只关注于一个特定的部分。
  • 人更易于理解多项简单的东西,而不是一项复杂的东西。
  • 保持子程序的短小精悍可以减小大脑的负担,在抽象层上工作也可以减小大脑的负担。

    如何应对复杂度

    高代价,低效率的设计的三个根源

  • 用复杂的方法解决简单的问题
  • 用简单但错误的方法解决复杂的问题
  • 用不恰当的复杂方法解决复杂的问题 正确的方法
  • 把本质的复杂度降至最低
  • 尽可能减少偶然性复杂度

    理想的设计特征

  • 最小的复杂度

    如果你的设计方案不能让你在专注于程序的一部分时,忽略其它部分,那么这样的设计就是有问题的

  • 易于维护
  • 松散耦合

    相互关联的类尽可能的少

  • 可扩展性
  • 可重用性
  • 高扇入 (一个底层的类被大量的引用)
  • 低扇出 (一个类少量的用其它的类)
  • 可移植性
  • 精简性
  • 层次性 (各个层次保持概念的完整性)

    如果旧代码不合理,编写一个新系统时,封装一层来调用旧代码

  • 标准技术 (尽可能的用标准技术)

    设计的层次

    设计分为五层

  • 软件系统设计
  • 分解为子系统和包
  • 分解为类
  • 分解为子程序
  • 子程序的详细设计

    在分解子系统时如果让子系统之间可以的相互通信,那么就失去了分解的意义。应当规定子系统之间的通信规则。

信息隐藏

隐藏的是某个易变的区域,某种文件格式,某种数据类型,某个隔离区域, 把这些易变信息的影响限制在某个类或子程序内。 隐藏复杂度,隐藏变化源

信息隐藏的障碍

  • 信息过度分散
  • 循环依赖
  • 把类内数据误认为全局数据
  • 误认为的性能损耗 在编写类时,时常问自己“这个类需要隐藏什么”

    找出容易改变的区域

  • 找出看起来容易变化的项目
  • 把容易变化的项目分离出来
  • 把容易变化的项目隔离开

易变化的区域 业务规则 对硬件的依赖 输入输出 非标准的库 状态变量 (用枚举而不是布尔) 数据常量

预料不同程度的变化

不要把精力放在那些不太可能发生而又很难设计的变化上

首先找出那些对用户有用的尽可能小的子集,这一子集构成系统的核心,不易发生变化。接下来进行尽可能小的扩充,慢慢的扩充。

松散的耦合

模块之间的耦合关系应该松散到应该可以很容易的被其它模块使用。

耦合标准

  • 规模 这里的规模指的是模块之间的连接数。一个参数的子程序比六个参数的子程序的耦合性更低
  • 可见性 模块之间的关系应该是显著的。避免通过操作全局变量的方式来实现模块之间的关联,一个模块不应该了解其它模块的实现细节。
  • 灵活性 灵活性是指模块之间的连接是否容易改动。

简而言之,一个模块越容易被其它模块调用,那么它们之间的耦合性就越松散。

耦合的种类

下面的耦合关系递增排列

  1. 简单参数数据耦合 (两个对象传的参数都是基本类型的数据)
  2. 简单对象耦合 (一个模块实例化一个对象)
  3. 对象参数耦合 (Object1 要求 Object2 传一个Object3给它)
  4. 语义上的耦合 (最难缠的耦合关系)
    • Model1传个控制标志给Model2,告诉Model2应该做什么。 这种方法要求Model1对Model2的工作细节有了解。 参数是枚举或对象会好一些
    • Model2修改了某个全局数据之后,Model1使用它。
    • Model1要求它的Initialize方法必须在它的Routin方法之前调用。Model2知道Routin方法会去调用Initialize方法,所以Model2不调用Initialize
    • Model1传个部分初始化的Object给Model2,因为它知道Model2只使用Object 7个方法中的3全方法,只用到其中的部分数据。
    • Modle1传个BaseObject, Model2知道是DerivedObject,强制转成DerivedObject,然后使用DerivedObject的方法

语义上的耦合是非常危险的,因为更改被调用的模块会破坏调用的模块,而这种错误是编译器无法检查的。 松耦合在于一个模块提供了一种间接层次的抽象,另一个模块可以放心的使用它,而不用管里面的细节

设计模式的益处

  • 设计模式通过提供现成的抽象来减小复杂度
  • 设计模式通过把常见的解决方案的细节予以制度化来减小出错
  • 设计模式通过多种设计方案而带来启发性的价值
  • 设计模式通过把设计对话提高到一个更高的层次来简化交流

    其它启发式方法

  • 高内聚性
  • 构造分层结构
  • 严格描述类契约
  • 分配职责 (单一职责)
  • 为测试而设计 (为了更容易测试,须要模块化,松耦合)
  • 避免失误
  • 有意识的选择绑定时间
  • 创建中央控制点 (控制可以集中在类,子程序,甚至具名常量里。这样为了找到某样事物,你需要查找的地方越少)
  • 画图
  • 保持设计的模块化
  • 使用蛮力

记录你的设计成果

  • 把设计文档插入到代码中。(文档少的情况下,JavaDoc可以生成文档)
  • 用Wiki来记录设计的决策
  • 写总结邮件 (写完发给项目组的所有人,维持一个邮件列表)
  • 用数码相机 拍下画板上的设计图,这种比在电脑上画图高效
  • 在适当的细节使用UML图

Comments