无论是以何种方式来进行设计,小型项目也能和大型项目一样从精心的设计之中获益,而如果能认识到设计是一项明确的活动,你就更会获益匪浅。
设计过程充满了不确定性,因此设计技术也趋于探索性质
软件的首要技术使命:管理复杂度
设计特征:
- 最小复杂度
- 易于维护
- 松散耦合
- 可扩展性
- 可重用性
- 高扇入:大量的类使用某个给定的类
- 低扇出:一个类里少量/适量地使用其他的类
- 可移植性
- 精简性
- 层次性
- 标准技术:尽量少依赖外来的,尽量使用标准的、常用的
系统层设计图应该是无环图
抽象是一种能让你在关注某一概念的同时可以放心地忽略其中一些细节的能力——在不同的层次处理不同的细节。抽象的主要好处就在于它使得你能忽略无关的细节,抽象是我们用来得以处理现实世界中复杂度的一种重要手段
在设计一个类的时候,一项关键性的决策就是确定类的哪些特性应该对外可见,而哪些特性应该隐藏起来 (面向对象设计的原则)
信息隐藏中所说的秘密主要分为两大类:
- 隐藏复杂度,
- 隐藏变化源
把容易变化的地方隔离开来
- 业务规则
- 对硬件的依赖性
- 输入和输出
- 非标准的语言特性
- 困难的设计区域和构建区域
- 状态变量
常用的设计模式
- 抽象工厂(Absctruct Factory):通过制定对象组的种类而非对单个对象的类型来支持创建一组相关的对象
- 适配器(Adapter):把一个类的接口转变成另一个接口
- 桥接(Bridge):把接口和实现分离开来,使他们可以独立变化
- 组合(Composite):创建一个包含其他同类对象的对象,使得客户端代码可以与最上层对象交互而无需考虑所有的细节对象
- 装饰器(Deractor):给一个对象动态的添加职责,而无需为了每一种可能的职责配置情况去创建特定的子类(派生类)
- 外观(Facade):为没有提供一致接口的代码提供一个一致的接口
- 工厂方法(Factory Method):做特定基类的派生类的实例化时,除了在Factory Method内部之外均无需了解各派生对象的具体类型
- 观察者(Observer):使一组相关对象相互同步,方法是让另一个对象负责:在这组对象中的任何一个发生改变时,由它把这种变化通知给这个组里的所有对象
- 单例模式(Singleton):为有且仅有一个实例的类提供一种全局访问的可能
- 策略(Strategy):定义一组算法或者行为,使得他们可以动态地相互替换
- 迭代方法(Iterator):提供一个服务对象来顺序的访问一组元素中的各个元素
- 模板方法(Template Method):定义一个操作的算法结构,但是把部分实现的细节留给子类(派生类)
设计模式的益处
- 设计模式通过提供抽象来减少复杂度
- 设计模式通过把常见解决方案的细节予以制度化来减少出错
- 设计模式通过提供多种设计方案而带来启发性价值
- 设计模式通过把设计对话提升到一个更高的层次上来简化交流
设计模式的陷阱
- 强迫让代码适用于某个模式
- 为了模式而模式
设计中启发式方法的总结:
- 寻找现实世界的对象
- 形成一致的抽象
- 封装实现细节
- 在可能的情况下继承
- 信息隐藏
- 找出容易改变的区域
- 保持松散的耦合
- 探寻通用的设计模式
- 高内聚性
- 构造分层结构
- 严格描述这类契约
- 分配职责
- 为测试而设计
- 避免失误
- 有意识地选择绑定时间
- 创建中央控制点
- 考虑蛮力
- 画一个图
- 保持设计模块化
解决问题的方法
- 理解问题
- 设计一个计划,找出现有数据和未知量之间的关系
- 执行计划
4.回顾
实际上,如果你尝试了一些设计方案,但没有很好的解决问题的时候,更自然的方式是让那些问题留在未解决的状态,等到你拥有更多信息之后再去做
迭代、分而治之、自上而下(分解)、自下而上(合成)
记录你的设计成果
- 把设计文档插入到代码
- 用wiki来记录设计讨论和决策
- 写总结邮件
- 使用数码相机
- 保留设计挂图
- 使用CRC卡片
- 在适当的细节层创建UML图
核对表:软件构造中的设计
设计实践
- 你已经做过多少次迭代,并且从众多尝试结果中选择最佳的一种,而不是简单选择第一次尝试的结果吗
- 你尝试用多种方案来分解系统,以确定最佳方案吗?
- 你同时用自上而下和自下而上的方法来解决涉及到的问题吗?
- 为了解决某些特定的问题,你对系统中的风险部分或者不熟悉的部分创建过原型、写出数量最少的可抛弃的代码吗?
- 你的设计方案被其他人检查了吗(无论正确与否)?
- 你一直在展开设计,直到实施细节跃然纸上了吗?
- 你用某种适当的技术——比如说wiki、电子邮件、挂图、数码照片、UML、CRC卡片或者在代码里写注释——来保留设计成果吗?
设计目标
- 你的设计是否充分地处理了由系统架构层定义出并且推迟确定的事项?
- 你的设计被划分为层次吗?
- 你对把这一程序分解成为子程序、包、类的方式感到满意吗?
- 类与类之间的交互关系是否已经设计为最小化了?
- 类和子程序是否被设计为能够在其他的系统中重用?
- 程序是不是易于维护
- 设计是否精简?设计出来的每一部分都是绝对必要的吗?
- 设计中是否采用了标准的技术?是否避免了使用怪异且难以理解的元素?
- 整体而言,你的设计是否有助于最小化偶然性的和本质性的复杂度吗?
要点
- 软件的首要技术使命就是管理复杂度。以简单作为努力目标的设计方案对此最有帮助
- 简单性可以通过两种方式获取:一是减少在同一时间所关注的本质性复杂度的量;而是避免生成不必要的偶然的复杂度
- 设计是一种启发式的过程。固执于某一种单一方法会损害创新能力,从而损害你的程序
- 好的设计都是迭代的。你尝试设计的可能性越多,你的最终分设计方案就会变得越好、
- 信息隐藏是个非常有价值的概念。通过询问“我应该隐藏什么?”能够解决很多困难的设计问题