一、面向复用的软件构造技术
▪ 软件复用是什么?
软件复用是利用现有的软件组件、模块或系统的能力,在不同的应用中多次使用这些组件,以节省开发时间、提高质量和降低成本的过程。
▪ 如何衡量“可复用性”?
衡量软件可复用性的方法通常包括代码的灵活性、模块的独立性、接口的清晰度、以及组件的通用性和泛化程度等方面的评估。
▪ 可复用组件的级别和形态
– 源代码级别的复用
– 模块级别的复用:类/接口
– 库级别的复用:API/包
– 系统级别的复用:框架
▪ 设计可复用的类
– 继承和重写
– 方法重载
– 参数多态性和泛型编程
– 行为子类型和里氏替换原则(LSP)
– 组合和委托
▪ 设计系统级别的可复用库和框架
– API 和库
– 框架
二、面向可维护性的构造技术
软件维护与演进
▪ 可维护性的度量标准
▪ 模块化设计与模块化原则
▪ 面向对象设计原则:SOLID
▪ 基于语法的构建
– 在计算机科学中,机器处理的文本语言无处不在。
– 语法是描述这些语言的最流行的形式。
– 正则表达式是语法的重要子类,可以在没有递归的情况下表达。
三、面向可复用性和可维护性的设计模式
可复用性:
Iterator 迭代器模式
实现方式是在ADT类中实现Iterable
接口,该接口内部只有一个返回一个迭代器的方法,然后创建一个迭代器类实现Iterator接口,实现hasnext()
、next()
、remove()
这三个方法。
Template Method 模板方法模式
- 框架:白盒框架
- 做事情的步骤一样,但具体方法不同
- 共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现
- 使用继承和重写实现模板模式
Strategy 策略模式
- 有多种不同的算法来实现同一个任务
- 但需要client根据需要动态切换算法,而不是写死在代码里
- 为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例
facade 外观模式
- 客户端需要通过一个简化的接口来访问复杂系统内的功能
- 提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用
- 便于客户端学习使用,解耦
Decorator 装饰者模式
- 为对象增加不同侧面的特性
- 对每一个特性构造子类,通过委派机制增加到对象上
- 客户端需要一个具有多种特性的object,通过逐层的装饰来实现
Adapter 适配器模式
- 将某个类/接口转换为client期望的其他形式
- 增加接口
- 通过增加一个接口,将已存在的子类封装起来
- client面向接口编程,从而隐藏了具体子类
可维护性:
Memento 备忘录模式
- 记住对象的历史状态,以便于“回滚”
- defines three distinct roles
- 需要“备忘”的类
- 添加originator的备忘记录和恢复
- 备忘录,记录originator对象的历史状态
- 需要“备份”的ADT的rep中只记录当前状态
- 每次“备份”都生成一个外部的Memento对象
Caretaker
负责掌控全部的状态备份,客户端通过它来操纵ADT的状态备份与恢复
State 状态模式
- 最好不要使用if/else结构在ADT内部实现状态转换(考虑将来的扩展和修改)
- 使用delegation,将状态转换的行为委派到独立的state对象去完成
Visitor 访问者模式
对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类
本质上:将数据和作用于数据上的某种/些特定操作分离开来
为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT
Observer 观察者模式
- 本ADT随时获取另一ADT状态变化
- 一对多广播
- “偶像”对“粉丝”广播
- 需要广播的ADT记录着所有观察自己的Observer,在自己状态变化时,对于每个Observer调用其
Update()
方法进行更新,即获取该ADT的状态变化
Proxy 代理模式
- 某个对象比较“敏感”/“私密”/“贵重”,不希望被client直接访问到,故设置proxy,在二者之间建立防火墙。
Abstract Factory 抽象工厂模式
提供接口以创建一组相关/相互依赖的对象,但不需要指明其具体类。
创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的object,各产品创建过程对client可见,但“搭配”不能改变。
本质上,Abstract Factory是把多类产品的factory method组合在一起
Factory Method 工厂方法模式
- 当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
- 定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。