结构型模式 Structural Patterns
外观模式 Facade Pattern
- 模式动机
- 引入一个外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色统一处理,从而降低系统耦合度
- 模式定义
- 外观模式:外部与一个子系统的通信必须通过一个统一的外观对象进行
- 为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
- 又称为门面模式
- 是一种对象结构型模式
- 模式结构
- Facade 外观角色
- SubSystem 子系统角色
- Client 客户类

- 模式分析
- 根据单一职责原则,将系统划分为若干个子系统有利于降低整个系统复杂性
- 一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小,引入外观对象就是一种实现方式,为子系统的访问提供了一个简单而单一的入口
- 外观模式也是迪米特法则的体现:通过引入外观类,降低原有系统的复杂度,同时降低客户类与子系统类的耦合度
- 外观类将客户端与子系统内部复杂性分隔开,客户端只需要与外观对象打交道
- 外观模式的目的在于降低系统复杂程度,提高客户端使用的便捷性
- 典型代码
public class Facade {
private SubSystemA obj1 = new SubSystemA();
private SubSystemB obj2 = new SubSystemB();
private SubSystemC obj3 = new SubSystemC();
public void method() {
obj1.method();
obj2.method();
obj3.method();
}
}
- 模式实例
- 电源总开关:一个总开关控制多盏灯、风扇、空调、电视机的启动和关闭
- 文件加密:加密流程包括读取源文件、加密、保存加密文件,客户端通过统一的加密外观类完成整个流程
- 模式优缺点
- 优点
- 对客户屏蔽子系统组件,减少客户处理的对象数量,使子系统使用起来更加容易
- 实现了子系统与客户之间的松耦合关系,子系统组件变化一般不会影响客户端,只需要调整外观类
- 降低大型软件系统中的编译依赖性,并简化系统在不同平台之间的移植过程
- 外观类只是提供统一入口,并不影响用户直接使用子系统类
- 缺点
- 不能很好地限制客户使用子系统类,如果限制太多又会降低可变性和灵活性
- 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端源代码,违背开闭原则
- 优点
- 模式适用环境
- 当要为一个复杂子系统提供一个简单接口时
- 客户程序与多个子系统之间存在很大的依赖性,需要通过外观类解耦
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,使层与层之间通过外观类建立联系,降低层间耦合度
- 模式应用
- JDBC 数据库操作可以封装为
JDBCFacade,统一提供open、executeUpdate、executeQuery、close等方法 - Java EE 中的 Session Facade,客户端通过会话外观访问业务对象
- JDBC 数据库操作可以封装为
- 模式扩展
- 一个系统可以有多个外观类
- 通常情况下一个子系统只需要一个外观类,而且外观类常被设计为单例类
- 但一个系统中也可以设计多个外观类,每个外观类负责与特定子系统交互,提供相应业务功能
- 不要试图通过外观类为子系统增加新行为
- 外观模式的用意是为子系统提供集中化、简化的沟通渠道
- 新行为应该通过修改原有子系统类或增加新的子系统类实现,而不是通过继承外观类实现
- 外观模式与迪米特法则
- 外观类充当客户类与子系统类之间的“第三者”
- 它把客户端涉及的子系统协作伙伴数量降到最低,是实现迪米特法则的一种常用重构方式
- 抽象外观类的引入
- 为解决外观模式违背开闭原则的问题,可以引入抽象外观类
- 客户端针对抽象外观类编程
- 新业务需求到来时,不修改原有外观类,而新增具体外观类,并通过配置文件更换外观对象
- 一个系统可以有多个外观类

享元模式 Flyweight Pattern
- 模式动机
- 面向对象技术可以提高系统灵活性和可扩展性,但在很多情况下会导致类和对象数量增加
- 当对象数量太多时,系统运行代价过高,可能带来性能下降
- 享元模式通过共享技术实现相同或相似对象的重用
- 享元模式的目的就是使用共享技术实现大量细粒度对象的复用
- 内部状态与外部状态
- 内部状态 Intrinsic State
- 存储在享元对象内部,不会随环境改变而改变
- 因此内部状态可以共享
- 外部状态 Extrinsic State
- 随环境改变而改变,不可以共享
- 外部状态必须由客户端保存,并在需要使用时传入享元对象内部
- 享元模式共享的是享元对象的内部状态,外部状态由外部环境设置
- 因为能够共享的内部状态有限,所以享元对象一般设计为较小的细粒度对象
- 内部状态 Intrinsic State
- 模式定义
- 享元模式:运用共享技术有效地支持大量细粒度对象的复用
- 系统只使用少量对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用
- 又称为轻量级模式
- 对象结构型模式
- 模式结构
- Flyweight 抽象享元类
- ConcreteFlyweight 具体享元类
- UnsharedConcreteFlyweight 非共享具体享元类
- FlyweightFactory 享元工厂类

- 模式分析
- 享元模式是一个考虑系统性能的设计模式
- 使用享元模式可以节约内存空间,提高系统性能
- 享元模式的核心在于享元工厂类
- 享元工厂类维护一个享元池 Flyweight Pool
- 用户需要对象时,先从享元池中获取
- 如果享元池中存在,则直接返回已有对象
- 如果享元池中不存在,则创建新的享元对象,放入享元池,再返回给用户
- 享元工厂类维护一个享元池 Flyweight Pool
- 典型代码
public class FlyweightFactory {
private HashMap flyweights = new HashMap();
public Flyweight getFlyweight(String key) {
if (flyweights.containsKey(key)) {
return (Flyweight) flyweights.get(key);
} else {
Flyweight fw = new ConcreteFlyweight();
flyweights.put(key, fw);
return fw;
}
}
}
public class Flyweight {
private String intrinsicState;
public Flyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
public void operation(String extrinsicState) {
// 使用内部状态和外部状态完成操作
}
}
- 模式实例
- 共享网络设备(无外部状态):多台终端计算机共享交换机、集线器等网络设备
- 共享网络设备(有外部状态):网络设备可以共享,但每台终端使用的端口不同,端口作为外部状态传入
- 模式优缺点
- 优点
- 极大减少内存中对象的数量
- 相同对象或相似对象在内存中只保存一份
- 外部状态相对独立,不影响内部状态,使享元对象可以在不同环境中共享
- 缺点
- 需要分离内部状态和外部状态,使系统更加复杂,程序逻辑复杂化
- 为了使对象可以共享,需要将享元对象的状态外部化
- 读取外部状态可能使运行时间变长
- 优点
- 模式适用环境
- 一个系统有大量相同或相似对象,由于大量使用造成内存大量耗费
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中
- 享元模式需要维护享元池,只有在多次重复使用享元对象时才值得使用
- 模式应用
- 编辑器软件中多次出现相同图片时,只需创建一个图片对象,通过设置不同显示位置来重复使用
- JDK 中的
String类使用了享元思想,例如字符串常量池
- 模式扩展
- 单纯享元模式
- 所有享元对象都可以共享
- 所有抽象享元类的子类都可共享,不存在非共享具体享元类
- 复合享元模式
- 将一些单纯享元通过组合模式加以组合,形成复合享元对象
- 复合享元对象本身不能共享,但可以分解成可以共享的单纯享元对象
- 与其他模式联用
- 享元工厂类中通常提供静态工厂方法返回享元对象,因此常与简单工厂模式联用
- 系统中通常只有一个享元工厂,因此享元工厂类可以使用单例模式设计
- 享元模式可以结合组合模式形成复合享元模式,统一对享元对象设置外部状态
- 单纯享元模式
代理模式 Proxy Pattern
- 模式动机
- 在某些情况下,客户端不想或者不能直接引用某个对象
- 此时可以通过一个称为代理的第三者来实现间接引用
- 代理对象可以在客户端和目标对象之间起到中介作用
- 代理对象既可以去掉客户不能看到的内容和服务,也可以添加客户需要的额外服务
- 引入代理对象来间接访问一个对象,就是代理模式的动机
- 模式定义
- 代理模式:给某一个对象提供一个代理,并由代理对象控制对原对象的引用
- 代理模式英文叫做 Proxy 或 Surrogate
- 对象结构型模式
- 模式结构
- Subject 抽象主题角色
- Proxy 代理主题角色
- RealSubject 真实主题角色
- Client 客户类

- 模式分析
- 抽象主题角色声明真实主题和代理主题的共同接口
- 代理主题角色内部包含对真实主题的引用,从而可以在任何时候操作真实主题对象
- 真实主题角色定义代理角色所代表的真实对象,在真实主题角色中实现真正的业务操作
- 客户端通过代理主题角色间接调用真实主题角色中的方法
- 代理类一般会在调用真实主题方法之前或之后执行额外操作
- 典型代码
public class Proxy implements Subject {
private RealSubject realSubject = new RealSubject();
public void preRequest() {
// 调用真实对象之前的操作
}
public void request() {
preRequest();
realSubject.request();
postRequest();
}
public void postRequest() {
// 调用真实对象之后的操作
}
}
- 模式实例
- 论坛权限控制代理
- 已注册用户和游客权限不同
- 使用保护代理控制对真实权限对象的访问,为不同用户提供不同级别权限
- 数学运算代理
- 远程对象实现加减乘除等运算
- 本地通过代理调用远程对象方法,模拟远程代理
- 论坛权限控制代理
- 模式优缺点
- 优点
- 能够协调调用者和被调用者,在一定程度上降低系统耦合度
- 远程代理使客户端可以访问远程机器上的对象
- 虚拟代理通过使用小对象代表大对象,减少系统资源消耗,优化系统并提高运行速度
- 保护代理可以控制对真实对象的使用权限
- 缺点
- 在客户端和真实主题之间增加代理对象,有些类型的代理模式可能造成请求处理速度变慢
- 实现代理模式需要额外工作,有些代理模式实现非常复杂
- 优点
- 模式适用环境 / 常见类型
- 远程代理 Remote Proxy
- 为位于不同地址空间的对象提供一个本地代理对象
- 又称为大使 Ambassador
- 虚拟代理 Virtual Proxy
- 如果需要创建资源消耗较大的对象,可以先创建一个消耗较小的对象来表示
- 真实对象只在需要时才真正创建
- Copy-on-Write 代理
- 虚拟代理的一种
- 将复制或克隆操作延迟到客户端真正需要时才执行
- 保护代理 Protect / Access Proxy
- 控制对一个对象的访问,可以给不同用户提供不同级别的使用权限
- 缓冲代理 Cache Proxy
- 为某个目标操作结果提供临时存储空间,使多个客户端可以共享结果
- 防火墙代理 Firewall Proxy
- 保护目标对象,不让恶意用户接近
- 智能引用代理 Smart Reference Proxy
- 当一个对象被引用时,提供额外操作,例如记录对象被调用次数
- 远程代理 Remote Proxy
- 模式应用
- Java RMI 远程方法调用
- EJB、Web Service 等分布式技术
- EJB 中远程服务器中的企业级 Bean 在本地有桩代理,客户端通过桩调用远程对象方法,而不需要直接与远程对象交互
- 模式扩展
- 远程代理
- 可以隐藏网络通信细节,使客户端不必考虑网络存在
- 客户端可以像使用本地对象一样使用远程业务对象
- 虚拟代理
- 当对象加载非常耗费资源时,先用代理对象代替真实对象初始化
- 可以节省内存并加快系统启动速度
- 常见例子是大图浏览:先加载小图片,后台加载大图,需要查看时再显示真实大图
- 远程代理
英文补充 English Supplement
Facade Pattern 外观模式
英文定义:
Provide a unified interface to a set of interfaces in a subsystem.
Facade defines a higher-level interface that makes the subsystem easier to use.
中文意思:
为子系统中的一组接口提供一个统一接口。外观定义了一个更高层的接口,使子系统更容易使用。
别名:
Facade
门面模式
核心术语:
| English | 中文 | 说明 |
|---|---|---|
| Facade | 外观角色 | 客户端直接调用的统一入口 |
| Subsystem | 子系统角色 | 实现具体功能的一组类或对象 |
| Client | 客户端 | 通过 Facade 使用子系统功能 |
| unified interface | 统一接口 | 对复杂子系统提供一致入口 |
| higher-level interface | 高层接口 | 简化客户端调用的接口 |
关键句:
Facade simplifies access to a subsystem but does not prevent direct access to subsystem classes.
外观模式简化对子系统的访问,但不禁止客户端直接访问子系统类。
考试表达:
- Facade Pattern reduces coupling between clients and subsystems.
- Facade Pattern is an application of the Law of Demeter.
- Facade provides a simple entry point to a complex subsystem.
- Without an abstract facade, adding new subsystems may violate the Open-Closed Principle.
Flyweight Pattern 享元模式
英文定义:
Use sharing to support large numbers of fine-grained objects efficiently.
中文意思:
运用共享技术有效地支持大量细粒度对象。
别名:
Lightweight Pattern
轻量级模式
核心术语:
| English | 中文 | 说明 |
|---|---|---|
| Flyweight | 抽象享元 | 声明接受外部状态的接口 |
| ConcreteFlyweight | 具体享元 | 可共享的享元对象 |
| UnsharedConcreteFlyweight | 非共享具体享元 | 不可共享的享元对象 |
| FlyweightFactory | 享元工厂 | 创建并管理享元池 |
| Flyweight Pool | 享元池 | 保存可共享对象 |
| Intrinsic State | 内部状态 | 存在对象内部,可以共享 |
| Extrinsic State | 外部状态 | 由外部传入,不可共享 |
关键句:
Flyweight shares intrinsic state and externalizes extrinsic state.
享元模式共享内部状态,并将外部状态外部化。
考试表达:
- Flyweight Pattern is useful when a system has many similar objects.
- It reduces memory usage by sharing objects.
- It requires separating intrinsic state from extrinsic state.
- It may increase complexity and runtime cost for passing external state.
Proxy Pattern 代理模式
英文定义:
Provide a surrogate or placeholder for another object to control access to it.
中文意思:
为另一个对象提供一种代理或占位符,以控制对这个对象的访问。
别名:
Surrogate
替身 / 代理
核心术语:
| English | 中文 | 说明 |
|---|---|---|
| Subject | 抽象主题 | 声明真实主题和代理主题的共同接口 |
| Proxy | 代理主题 | 持有 RealSubject 引用,控制访问 |
| RealSubject | 真实主题 | 真正执行业务逻辑的对象 |
| surrogate | 代理 / 替身 | 替真实对象接受请求 |
| placeholder | 占位符 | 在真实对象创建或访问前代表它 |
| control access | 控制访问 | 代理模式的核心目的 |
关键句:
Proxy controls access to an object, while Decorator adds responsibilities to an object.
代理模式控制对象访问,装饰模式给对象增加职责。
常见代理类型:
| Type | 中文 | 作用 |
|---|---|---|
| Remote Proxy | 远程代理 | 为远程对象提供本地代表 |
| Virtual Proxy | 虚拟代理 | 延迟创建昂贵对象 |
| Protection Proxy | 保护代理 | 控制访问权限 |
| Cache Proxy | 缓冲代理 | 缓存目标操作结果 |
| Firewall Proxy | 防火墙代理 | 阻止恶意访问 |
| Smart Reference Proxy | 智能引用代理 | 对对象引用增加额外操作 |
考试表达:
- Proxy and RealSubject implement the same Subject interface.
- The client talks to Proxy instead of RealSubject directly.
- Proxy may perform pre-processing and post-processing around the real request.
- Proxy may improve security or resource usage, but it may also slow down request processing.
Facade vs Proxy vs Decorator
| Pattern | 中文 | 核心目的 | 结构特点 |
|---|---|---|---|
| Facade | 外观模式 | 简化对子系统的访问 | 一个外观对象封装多个子系统对象 |
| Proxy | 代理模式 | 控制对某个对象的访问 | 代理和真实对象实现同一接口 |
| Decorator | 装饰模式 | 动态增加对象职责 | 装饰者和被装饰者实现同一接口,装饰者持有构件 |
一句话区分:
Facade simplifies, Proxy controls, Decorator extends.
外观负责简化,代理负责控制,装饰负责扩展。