设计模式
设计模式笔记
设计模式六大原则
开闭原则
对扩展开放,对修改关闭
1. 单一职责原则
每个类只实现了一种单一的职责,如果有多个职责,应该将其拆分成多个类
2. 里氏替换原则
所有引用基类的地方必须能透明地使用其子类的对象
子类必须实现父类的抽象方法,不能重写父类已经实现的方法
子类可以增加自己的方法
当子类覆盖或实现父类的方法时,方法的形参应该更加宽松
3. 依赖倒转原则
高层模块不应该依赖底层模块,两者应该依赖其抽象(接口)
抽象(接口)不应该依赖其细节(实现类)
细节应该依赖抽象
4. 接口隔离原则
每一个接口都不存在子类用不到但必须实现的方法,如果有,则应该将其拆分成多个接口
5. 迪米特法则
一个类对自己依赖的类知道的越少越好
逻辑方法封装在内部,仅通过public开放部分方法给外部
6. 合成复用原则
尽量使用合成/聚合的方式而不是使用继承
合成或聚合可以将已有对象纳入到新对象中,使之成为新对象的一部分
创建模式
工厂模式
对象通过工厂类生成,而不是使用者主动调用构造方法生成
使用者使用对应的接口,并自己决定使用哪个实例化工厂获得该接口对应的实例化对象
每个实例化工厂只生产一种产品
抽象工厂模式
有多个工厂类, 每个工厂类产生一个系列的多种产品
和简单工厂的区别
简单工厂针对的是一个产品结构, 而抽象工厂针对的是产品族
简单工厂的工厂类只能产生一种产品, 而抽象工厂的工厂类能产生多种属于同一产品族的产品
简单工厂内有一个产品类就会有一种对应的工厂类, 而抽象工厂一须有一种工厂类
单例模式
通过静态方法赋值对象,所有使用该对象的地方使用的都是同一个对象
实例对象的构造方法为私有的,使用者无法直接调用构造方法生成对象
多线程的应用中需要添加线程锁
适用场景和优点
某些类创建比较频繁, 创建这些类对系统是很大一笔开销
省去了new操作, 降低了系统内存的使用频率, 减轻GC压力
建造者模式(生成器模式)
用户通过指定复杂对象类型和内容就可以构造产品类,不需要知道具体构建细节
包含角色:
名称 | 含义 |
---|---|
Productor 产品角色 | 具体的产品对象 |
Builder 抽象建造者 | 创建一个Productor对象各个部件的指定接口 |
ConcreateBuilder 具体建造者 | 实现抽象接口,构建和装备各个部件 |
Director 指挥者 | 构建一个使用Builder接口的对象,控制产品对象生产的过程 |
原型模式
使用拷贝的方式创建实例化对象,所有的实例化对象都是原型对象的拷贝
包含角色:
名称 | 含义 |
---|---|
Client | 使用者 |
Prototype | 抽象原型类接口, 声明局别clone的能力, 如java的cloneable接口 |
ConcretePrototype | 具体的原型类 |
适用场景
当new一个对象非常繁琐时, 可以使用原型模式来复制一个对象, 即时需求的变更, 这些对象需>>
要作出调整, 我们依然有比较稳定一直的接口创造对象需要提供数据对象, 同时又需要避免外部对数据对向进行修改
结构性模式
适配器模式(包装器模式)
将某个类的接口转化为用户期望的另一个接口表示, 让原本接口不匹配而不能一起工作的两个类可以协同工作
类适配器模式
通过继承src类,实现dst类接口,完成src->dst的适配
对象适配器模式
基本思路和类的适配器模式相同, 只是将Adapter类作修改, 这次不继承src类, 而是持有src类的实例
持有src类,实现dst类接口,完成src->dst的适配
接口适配器模式
实现src接口,完成src->dst的适配
当不需要实现所有接口的方法时, 可以将它的方法实现为空方法
适用场景
系统需要使用现有的类, 而这些类的接口不符合系统的要求
需要建立一个可重复使用的类, 用于与彼此之间没有太大关联的一些类, 包括将来可能会引进的类一起工作
类需要一个统一的输出接口, 而输入端的类型不可预知
装饰器模式
通过组合来实现代码复用, 而不是继承, 装饰器模式是继承的一种替代方案
要扩展的类A持有类B的引用, 通过在A中调用B的方法来实现代码的复用
包含角色:
名称 | 含义 |
---|---|
抽象构建角色 | 一个抽象接口, 以规范准备接受附加责任的对象 |
具体构建角色 | 定义一个将要接受附加责任的类 |
装饰角色 | 持有一个构件对象的实例, 并定义一个与抽象构建接口一致的接口 |
具体装饰角色 | 负责给构建对象贴上附加的责任 |
与适配器模式的区别
适配器模式的一一是将一个接口转变成另一个接口, 它的目的是通过改变接口来达到重复使用的目的
装饰器模式不是要改变装饰对象的接口, 而是在保留原有的接口的情况下, 扩展原有接口的功能, 或者改变原有对象的处理方法而提升性能
代理模式
通过代理对象来访问目标对象, 可以在目标对象实现的基础上, 增强额外的功能操作, 即扩展目标对象的功能
代理模式时面向切面编程AOP的基础
代理对象是对目标对象的扩展,并会调用目标对象
外观模式
外观模式影藏了系统的复杂性, 向用户提供了一个可以访问系统的接口
包含角色:
名称 | 含义 |
---|---|
门面角色 | 为外观模式的核心,内部根据客户角色的需求预定了几种功能的组合,被用客户角色调用, 熟悉子系统的功能 |
子系统角色 | 实现了子系统的功能, 对客户未知 |
客户角色 | 通过调用门面角色来完成要实现的功能 |
桥接模式
桥接模式将抽象部分与其实现部分分离, 使他们都可以独立的变化
包含角色:
名称 | 含义 |
---|---|
抽象化角色(Abstraction) | 定义抽象类, 斌包含一个队实现化对象的引用 |
扩展抽象化角色(Refined Abstraction) | 抽象化角色的子类, 实现父类的业务方法, 通过组合关系调用实现化角色中的业务方法 |
实现化角色(Implementor) | 定义实现化角色的接口, 扩展抽象化角色调用 |
具体实现化角色(Concrete Implementor) | 实现化角色的具体实现 |
组合模式
组合模式将对象组合成树形结构以表示“部分-整体”的层次结构, 使客户端对单个对象和组合对象保持一致的方式处理
包含角色:
名称 | 含义 |
---|---|
抽象构件(Component) | 叶子构件和容器构件的接口, 包含子类行为的声明和实现 |
叶子构件(Leaf) | 实现构件定义的行为 |
容器构件(Composite) | 含有所有的子节点, 子节点可能是叶子节点, 也可能是其他容器结点, 可以调用子节点的方法 |
适用场景及优点
忽略组合对象与单个对象的差异, 忽略层次的差异, 方便对整个层次结构进行控制
适用于树形结构
享元模式
初次使用时在池中创建对象, 以后要用到该角色时不需要新创建该对象, 只需要在其中引用池中的对象
享元模式是池技术基础
包含角色:
名称 | 含义 |
---|---|
抽象享元角色(Flyweight) | 产品的抽象类, 同时定义出对象的外部状态和内部状态 |
具体享元角色(ConcreteFlyweight) | 具体的产品类, 实现抽象角色定义的业务 |
享元工厂(FlyweightFactory) | 用于构造一个池容器, 同时提供从池中获得对象的方法 |
适用场景
系统中有大量对象时
对象消耗大量内存时
对象的状态大部分可以外部化时
行为型模式
责任链模式
将处理类形成一个链,处理信息沿着这条链传递该请求, 直到有一个对象处理他为止
包含角色:
名称 | 含义 |
---|---|
抽象处理者角色(Handler) | 定义处理请求的接口, 包含设定和返回下家的引用 |
具体处理着角色(ConcreteHandler) | 具体处理着接到请求后, 可以选择处理请求, 或者将请求传给下家 |
命令模式
命令模式将来自客户端的请求传入一个对象, 从而可用不同的请求对客户进行参数化
包含角色:
名称 | 含义 |
---|---|
命令接口(Command) | 定义命令的接口, 声明执行的方法 |
具体命令对象(ConcreteCommand) | 命令接口的实现对象, 通常是由接受者, 并调用接受者的功能 |
接受者(Receiver) | 真正执行命令的对象, 任何类都可以成为一个接受者, 只要它能实现命令要求实现的相应功能 |
调用者(Invoker) | 持有命令对象, 可以持有多个命令对象,是客户端真正触发命令并要求命令执行相应操作的地方, 是使用命令对象的入口 |
客户端(装配者)(Client) | 创建具体的命令对象, 并且设置命令对象的接受者, 组装命令对象和接收者 |
优点
降低对象之间的耦合度
新的命令可以很容易的加入到系统中
可以比较容易的设计一个组合命令
可以调用同一方法实现不同功能
备忘录模式
备忘录模式用于保存和恢复对象的状态,关键时刻可以进行对象状态的还原
包含角色:
名称 | 含义 |
---|---|
原发器(Originator) | 可以调用备忘录的所有信息 |
备忘录(Memento) | 记录对象的历史状态 |
负责人(Caretaker) | 只负责备忘录的保存并将备忘录传递给其他对象 |
状态模式
状态模式中,对象装填在多种状态切换, 状态的转换顺序是固定方向
包含角色:
名称 | 含义 |
---|---|
状态接口(State) | 相当于开关,包含切换状态的方法 |
具体状态角色(ConcreteState) | 状态管器接口的实现类 |
状态管理器(Context) | 调用状态接口, 控制状态的切换 |
访问者模式
封装某些作用于某种数据结构中各元素的操作, 可以在不改变数据结构的前提下定义作用于这些元素的新的操作
将数据结构和对应的操作方法进行解耦
包含角色:
名称 | 含义 |
---|---|
访问者接口 | 访问者接口, 通过visit方法声明访问者可以访问那些元素 |
访问者对象 | 访问者接口的实现类, 影响到访问者访问到一个类后该干什么, 要做什么事 |
元素类接口 | 声明accept方法,定义接受哪一类访问者访问 |
元素类对象 | 实现元素类接口, 实现accept方法, 通常是visitor.visit(this)形式 |
结构对象 | 一个元素的容器, 包含不同类和接口 |
中介者模式
用一个中介者对象封装一系列的对象交互, 中介者使各对象不需要显示地相互作用, 从而使耦合松散, 而且可以独立地改变它们之间的交互
解释器模式
解释器模式提供了评估语言的语法或表达式的方式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文
多用于编译器和表达式解析
包含角色:
名称 | 含义 |
---|---|
抽象表达式(AbstractExpression) | 声明了抽象的解释操作 |
终结符表达式(TerminalExpression) | 实现了抽象表达式接口,实现了与文法的终结符相关的解释操作, 在句中的每一个终结符都是该类的一个实例 |
非终结符表达式(NoterminalExpression) | 实现了抽象表达式接口,实现了与文法的非终结符相关的解释操作, 在非中介表达式中可以包含终结符表达式, 也可以继续包含非终结符表达式, 解释器一般通过递归来完成 |
上下文类(环境类)(Context) | 用于存储解释器外的一些全局信息, 通常它临时存储了需要解释的语句 |