设计模式的作用
- 应用程序
- 框架
- 设计模式
- 创建模式,结构模式,行为模式
- OOD 原则
- OCP、DIP、LSP、SRP、ISP
- OOD 的目标
- 强内聚、低耦合的程序
设计模式的定义
什么是设计模式?
- 每一个模式都描述了一种问题的通用解决方案。这种问题在我们的环境中,不停的出现。
- 设计模式是一种可重复使用的解决方案。
一个设计模式的四个部分:
- 模式的名称-少量字组成,有助于表达设计。
- 待解问题-何时用以及运用模式的环境
- 解决方案-组成设计的元素、关系、职责以及合作。抽象,不代表具体的实现。
- 结论-该方案带来的利弊。指对系统的弹性、扩展性、和可移植性的影响。
设计模式的分类
从功能分
- 创建模式
- 对类的实例化过程的抽象。
- 结构模式
- 将类或者对象结合在一起形成更大的结构。
- 行为模式
- 对在不同的对象之间划分责任和算法的抽象化。
从方式分
- 类模式
- 以继承的方式实现模式,静态的。
- 对象模式
- 以组合的方式实现模式,动态的。
排序问题-如何创建一个对象
简单工厂模式
优点:
- 使 Client 不再依赖 Sorter 的具体实现
- 对 Client 实现 OCP - 增加 Sorter 不影响 Client
缺点:
- 对 Factory 未实现 OCP - 增加 Sorter 需要修改 Factory
简单工厂模式-改进一
写死的类加载获取。
解决的问题:
- 增加 Sorter 实现时,不需要修改 Factory
- 但仍然要改 Client
其它问题
- 丧失了编译时的类型安全
- Client 和 Factory 均类型不安全
- Client 仍然知道 Sorter 的实现是什么
- 限制了 Sorter 的实现智能通过默认构造函数创建
简单工厂模式-改进二
优点:
- 满足 OCP
- 对 Client 和 Factory 均满足
- 满足 OCP 方法
- 抽象
- 动态变成(将编译时类型检查转变成运行时检查)
缺点:
- 缺少编译时类型安全
- 限制了 Sorter 的实现智能通过默认构造函数创建
该机制解决了简单工厂模式最致命的问题
Singleton 单例模式
为什么要使用
Singleton 模式保证产生单一实例,即一个类只产生一个实例。
- 减少实例频繁创建和销毁带来的资源消耗;【性能需求】
- 当多个用户使用这个实例时,便于统一控制(比如打印机对象)【功能需求】
实现方法
- 静态类
- 加锁懒加载初始化
说明
- 必须有私有构造函数,保证类实例通过公有方法获取。
- 方法2要加锁关键字,避免产生多重实例。
- 尽量使用方法1构造单实例。
- 单例中成员变量是多线程重用的,可能会产生意想不到的结果,因此尽量将单例设计为无状态对象(只提供服务,不保存状态)。
适配器模式
适配器的作用:
- 系统需要使用现有的类,而这个类的接口与我们所需要的不同
- 例如:我们需要对 List 进行排序,但是我们需要一个 Sortable 的接口,原有的 List 即可不能满足要求。
适配器的应用:
- JDBC Driver
- 对具体数据库的适配器
- 比如,将 Oracle 适配到 JDBC 中
- JDBC-ODBC Bridge
- 是将 Windows ODBC 适配到 JDBC 接口中
JUnit 中的设计模式
实现一个单元测试的步骤
- 创建测试类,从 TestCase 派生
- 初始化:覆盖基类的方法:setUp
- 清除环境:覆盖基类方法:tearDown
- 书写测试方法:命名规则:testXyz
JUnit 单元测试是如何执行的
定义抽象类,继承 Assert,实现 Test。
模板方法模式
- 扩展功能的最基本模式之一
- 「类的行为模式」
通过继承的方式来实现扩展
- 基类负责算法的轮廓和骨架
- 子类负责算法的具体实现
组合 vs 继承
- 基于继承的模板方法比组合更容易实现
- 适当使用这种模式。
模板方法的形式
- 抽象方法
- abstract void step1()
- 强制子类实现该步骤
- 具体方法
- void doSomething(){…}
- 子类不需要覆盖,但也可以覆盖之
- 如想明确告诉子类「不需要覆盖它」,最好标明:final
- 钩子方法
- void setUp(){}
- 空的实现(缺省适配器模式)
- 子类可选择性地覆盖之,以便在特定的时机做些事。
举例
- Java Servlet 中模板方法
- JUnit 模板方法
策略模式
- 扩展功能的另一种最基本的模式
- 「对象的行为模式」
通过组合的方式来实现扩展。
使用场景
- 系统需要在多种算法中选择一种
- 重构系统时
- 将条件语句转换成对于策略的多态性调用
- 策略模式的优点(对比模板方法)
- 将使用策略的人与策略的具体实现分离
- 策略对象可以自由组合
- 策略模式的问题
- 仅封装了算法的具体实现,方便添加和替换算法。但它并不关心何时使用算法,必须由客户端来决定。
组合模式
- 对象的结构模式
举例:
- 文件系统
- AWT 控件
装饰器模式
- 对象的结构模式
作用:
- 在不改变对客户端接口的前提下(对客户端透明)
- 扩展现有对象的功能
装饰器模式也被笼统地称为「包装器」(Wrapper)
- 适配器也被称为包装器,区别在于适配器是转换成另一个接口,而装饰器是保持接口不变。
- 包装器形成一条链。
装饰器和模板、策略比较
- 装饰器保持对象的功能不变,扩展其外围的功能
- 模板和策略保持算法的框架不变,扩展其内部实现
装饰器和继承的比较
- 都可以扩展对象的功能
- 但装饰器是动态的,继承是静态的
- 装饰器可以任意组合
- 但这也使装饰器更复杂,有可能会组合出荒谬的结果
装饰器应用:
- Java servlet: HttpServletRequest/HttpServletRequestWrapper
- 同步化装饰器:Collections.synchronizedList(list)
- Java IO 类库:
- 流
- InputStream、OutputStream:字节流
- Reader、Writer:字符流