note's Introduction
note's People
note's Issues
Java虚拟机笔记
深入理解Java虚拟机:JVM高级特性与最佳实践. 机械工业出版社
自动内存管理机制
Java内存区域和内存溢出异常
程序计数器
- 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码指令
Java虚拟机栈
- 与计数器一样,Java虚拟机栈也是线程私有的。虚拟机栈描述的是Java方法执行的内存模型,每个方法执行时都会同时创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等,每个方法从调用直到执行完成就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
- 局部变量表存放了编译期可知的各种基本数据类型、对象引用、和returnAddress类型(指向下一条字节码指令的地址)
本地方法栈
- 与虚拟机栈相似,区别是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈为虚拟机使用到的native方法服务
Java堆
Java内存中最大的一块,Java堆被所有线程共享的一块内存区域,在虚拟机启动时创建,此 内 存 区 域 的 唯 一 目 的 就 是 存 放 对 象 实 例, 几 乎 所 有 的 对 象 实 例 都 在 这 里 分 配 内 存。Java 堆 是 垃 圾 收 集 器 管 理 的 主 要 区 域, 因 此 很 多 时 候 也 被 称 做“ GC 堆”。
方法区
- 方 法 区( Method Area) 与 Java 堆 一 样, 是 各 个 线 程 共 享 的 内 存 区 域, 它 用 于 存 储 已 被 虚 拟 机 加 载 的 类 信 息、 常 量、 静 态 变 量、 即 时 编 译 器 编 译 后 的 代 码 等 数 据。
运行时常量池
- 运 行 时 常 量 池( Runtime Constant Pool) 是 方 法 区 的 一 部 分。 Class 文 件 中 除 了 有 类 的 版 本、 字 段、 方 法、 接 口 等 描 述 信 息 外, 还 有 一 项 信 息 是 常 量 池( Constant Pool Table), 用 于 存 放 编 译 期 生 成 的 各 种 字 面 量 和 符 号 引 用, 这 部 分 内 容 将 在 类 加 载 后 进 入 方 法 区 的 运 行 时 常 量 池 中 存 放。
HotSpot虚拟机对象探秘
对象的创建
- 虚 拟 机 遇 到 一 条 new 指 令 时, 首 先 将 去 检 查 这 个 指 令 的 参 数 是 否 能 在 常 量 池 中 定 位 到 一 个 类 的 符 号 引 用, 并 且 检 查 这 个 符 号 引 用 代 表 的 类 是 否 已 被 加 载、 解 析 和 初 始 化 过。
- 如 果 没 有, 那 必 须 先 执 行 相 应 的 类 加 载 过 程,在 类 加 载 检 查 通 过 后, 接 下 来 虚 拟 机 将 为 新 生 对 象 分 配 内 存。 对 象 所 需 内 存 的 大 小 在 类 加 载 完 成 后 便 可 完 全 确 , 执 行 new 指 令 之 后 会 接 着 执 行 < init > 方 法, 把 对 象 按 照 程 序 员 的 意 愿 进 行 初 始 化, 这 样 一 个 真 正 可 用 的 对 象 才 算 完 全 产 生 出 来。
对象的内存布局
在 HotSpot 虚 拟 机 中, 对 象 在 内 存 中 存 储 的 布 局 可 以 分 为 3 块 区 域: 对 象 头( Header)、 实 例 数 据( Instance Data) 和 对 齐 填 充( Padding)。HotSpot 虚 拟 机 的 对 象 头 包 括 两 部 分 信 息, 第 一 部 分 用 于 存 储 对 象 自 身 的 运 行 时 数 据, 如 哈 希 码( HashCode)、 GC 分 代 年 龄、 锁 状 态 标 志、 线 程 持 有 的 锁、 偏 向 线 程 ID、 偏 向 时 间 戳 等,对 象 头 的 另 外 一 部 分 是 类 型 指 针, 即 对 象 指 向 它 的 类 元 数 据 的 指 针, 虚 拟 机 通 过 这 个 指 针 来 确 定 这 个 对 象 是 哪 个 类 的 实 例。
对象访问定位
- 由 于 reference 类 型 在 Java 虚 拟 机 规 范 中 只 规 定 了 一 个 指 向 对 象 的 引 用, 并 没 有 定 义 这 个 引 用 应 该 通 过 何 种 方 式 去 定 位、 访 问 堆 中 的 对 象 的 具 体 位 置, 所 以 对 象 访 问 方 式 也 是 取 决 于 虚 拟 机 实 现 而 定 的。 目 前 主 流 的 访 问 方 式 有 使 用 句 柄 和 直 接 指 针 两 种。如 果 使 用 句 柄 访 问 的 话, 那 么 Java 堆 中 将 会 划 分 出 一 块 内 存 来 作 为 句 柄 池, reference 中 存 储 的 就 是 对 象 的 句 柄 地 址, 而 句 柄 中 包 含 了 对 象 实 例 数 据 与 类 型 数 据 各 自 的 具 体 地 址 信 息,如 果 使 用 直 接 指 针 访 问, 那 么 Java 堆 对 象 的 布 局 中 就 必 须 考 虑 如 何 放 置 访 问 类 型 数 据 的 相 关 信 息, 而 reference 中 存 储 的 直 接 就 是 对 象 地 址,
垃圾收集器与内存分配策略
引用计数算法
- 给 对 象 中 添 加 一 个 引 用 计 数 器, 每 当 有 一 个 地 方 引 用 它 时, 计 数 器 值 就 加 1; 当 引 用 失 效 时, 计 数 器 值 就 减 1; 任 何 时 刻 计 数 器 为 0 的 对 象 就 是 不 可 能 再 被 使 用 的。但是它 很 难 解 决 对 象 之 间 相 互 循 环 引 用 的 问 题。
可达性分析算法
- 这 个 算 法 的 基 本 思 路 就 是 通 过 一 系 列 的 称 为" GC Roots" 的 对 象 作 为 起 始 点, 从 这 些 节 点 开 始 向 下 搜 索, 搜 索 所 走 过 的 路 径 称 为 引 用 链( Reference Chain), 当 一 个 对 象 到 GC Roots 没 有 任 何 引 用 链 相 连( 用 图 论 的 话 来 说, 就 是 从 GC Roots 到 这 个 对 象 不 可 达) 时, 则 证 明 此 对 象 是 不 可 用 的。
垃圾收集算法
标记-清除算法
- 算 法 分 为“ 标 记” 和“ 清 除” 两 个 阶 段:
- 首 先 标 记 出 所 有 需 要 回 收 的 对 象, 在 标 记 完 成 后 统 一 回 收 所 有 被 标 记 的 对 象
- 它 是 最 基 础 的 收 集 算 法, 是 因 为 后 续 的 收 集 算 法 都 是 基 于 这 种 思 路 并 对 其 不 足 进 行 改 进 而 得 到 的。
- 它 的 主 要 不 足 有 两 个: 一 个 是 效 率 问 题, 标 记 和 清 除 两 个 过 程 的 效 率 都 不 高; 另 一 个 是 空 间 问 题, 标 记 清 除 之 后 会 产 生 大 量 不 连 续 的 内 存 碎 片, 空 间 碎 片 太 多 可 能 会 导 致 以 后 在 程 序 运 行 过 程 中 需 要 分 配 较 大 对 象 时, 无 法 找 到 足 够 的 连 续 内 存 而 不 得 不 提 前 触 发 另 一 次 垃 圾 收 集 动 作。
复制算法
- 为 了 解 决 效 率 问 题, 一 种 称 为“ 复 制”( Copying) 的 收 集 算 法 出 现 了, 它 将 可 用 内 存 按 容 量 划 分 为 大 小 相 等 的 两 块, 每 次 只 使 用 其 中 的 一 块。
- 当 这 一 块 的 内 存 用 完 了, 就 将 还 存 活 着 的 对 象 复 制 到 另 外 一 块 上 面, 然 后 再 把 已 使 用 过 的 内 存 空 间 一 次 清 理 掉。 这 样 使 得 每 次 都 是 对 整 个 半 区 进 行 内 存 回 收, 内 存 分 配 时 也 就 不 用 考 虑 内 存 碎 片 等 复 杂 情 况, 只 要 移 动 堆 顶 指 针, 按 顺 序 分 配 内 存 即 可, 实 现 简 单, 运 行 高 效。 只 是 这 种 算 法 的 代 价 是 将 内 存 缩 小 为 了 原 来 的 一 半, 未 免 太 高 了 一 点。
标记-整理算法
- 标 记 过 程 仍 然 与“ 标 记-清 除” 算 法 一 样, 但 后 续 步 骤 不 是 直 接 对 可 回 收 对 象 进 行 清 理, 而 是 让 所 有 存 活 的 对 象 都 向 一 端 移 动, 然 后 直 接 清 理 掉 端 边 界 以 外 的 内 存,“ 标 记-整 理”
分代收集算法
- 当 前 商 业 虚 拟 机 的 垃 圾 收 集 都 采 用“ 分 代 收 集”( Generational Collection) 算 法,
- 根 据 对 象 存 活 周 期 的 不 同 将 内 存 划 分 为 几 块。 一 般 是 把 Java 堆 分 为 新 生 代 和 老 年 代, 这 样 就 可 以 根 据 各 个 年 代 的 特 点 采 用 最 适 当 的 收 集 算 法。
- 在 新 生 代 中, 每 次 垃 圾 收 集 时 都 发 现 有 大 批 对 象 死 去, 只 有 少 量 存 活, 那 就 选 用 复 制 算 法, 只 需 要 付 出 少 量 存 活 对 象 的 复 制 成 本 就 可 以 完 成 收 集。 而 老 年 代 中 因 为 对 象 存 活 率 高、
- 没 有 额 外 空 间 对 它 进 行 分 配 担 保, 就 必 须 使 用“ 标 记— 清 理” 或 者“ 标 记— 整 理” 算 法 来 进 行 回 收
安全点
- 程 序 执 行 时 并 非 在 所 有 地 方 都 能 停 顿 下 来 开 始 GC, 只 有 在 到 达 安 全 点 时 才 能 暂 停。需 要 考 虑 的 问 题 是 如 何 在 GC 发 生 时 让 所 有 线 程( 这 里 不 包 括 执 行 JNI 调 用 的 线 程) 都“ 跑” 到 最 近 的 安 全 点 上 再 停 顿 下 来。
- 抢 先 式 中 断( Preemptive Suspension
抢 先 式 中 断 不 需 要 线 程 的 执 行 代 码 主 动 去 配 合, 在 GC 发 生 时, 首 先 把 所 有 线 程 全 部 中 断, 如 果 发 现 有 线 程 中 断 的 地 方 不 在 安 全 点 上, 就 恢 复 线 程, 让 它“ 跑” 到 安 全 点 上。 现 在 几 乎 没 有 虚 拟 机 实 现 采 用 抢 先 式 中 断 来 暂 停 线 程 从 而 响 应 GC 事 件。 - 主 动 式 中 断( Voluntary Suspension)
主 动 式 中 断 的 思 想 是 当 GC 需 要 中 断 线 程 的 时 候, 不 直 接 对 线 程 操 作, 仅 仅 简 单 地 设 置 一 个 标 志, 各 个 线 程 执 行 时 主 动 去 轮 询 这 个 标 志, 发 现 中 断 标 志 为 真 时 就 自 己 中 断 挂 起。 轮 询 标 志 的 地 方 和 安 全 点 是 重 合 的, 另 外 再 加 上 创 建 对 象 需 要 分 配 内 存 的 地 方。
安全区域
- 安 全 区 域 是 指 在 一 段 代 码 片 段 之 中, 引 用 关 系 不 会 发 生 变 化。 在 这 个 区 域 中 的 任 意 地 方 开 始 GC 都 是 安 全 的。 我 们 也 可 以 把 Safe Region 看 做 是 被 扩 展 了 的 Safepoint。
垃圾收集器
如 果 说 收 集 算 法 是 内 存 回 收 的 方 法 论, 那 么 垃 圾 收 集 器 就 是 内 存 回 收 的 具 体 实 现。
连线代表可以搭配使用
Serial收集器
- 是 一 个 单 线 程 的 收 集 器, 但 它 的“ 单 线 程” 的 意 义 并 不 仅 仅 说 明 它 只 会 使 用 一 个 CPU 或 一 条 收 集 线 程 去 完 成 垃 圾 收 集 工 作, 更 重 要 的 是 在 它 进 行 垃 圾 收 集 时, 必 须 暂 停 其 他 所 有 的 工 作 线 程, 直 到 它 收 集 结 束。它 依 然 是 虚 拟 机 运 行 在 Client 模 式 下 的 默 认 新 生 代 收 集 器。
- 它 也 有 着 优 于 其 他 收 集 器 的 地 方: 简 单 而 高 效( 与 其 他 收 集 器 的 单 线 程 比), 对 于 限 定 单 个 CPU 的 环 境 来 说, Serial 收 集 器 由 于 没 有 线 程 交 互 的 开 销, 专 心 做 垃 圾 收 集 自 然 可 以 获 得 最 高 的 单 线 程 收 集 效 率。
ParNew收集器
- ParNew 收 集 器 其 实 就 是 Serial 收 集 器 的 多 线 程 版 本, 除 了 使 用 多 条 线 程 进 行 垃 圾 收 集 之 外, 其 余 行 为 包 括 Serial 收 集 器 可 用 的 所 有 控 制 参 数( 例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure 等)、 收 集 算 法、 Stop The World、 对 象 分 配 规 则、 回 收 策 略 等 都 与 Serial 收 集 器 完 全 一 样, 在 实 现 上, 这 两 种 收 集 器 也 共 用 了 相 当 多 的 代 码。
Parallel Scavenge收集器
Parallel Scavenge 收 集 器 是 一 个 新 生 代 收 集 器, 它 也 是 使 用 复 制 算 法 的 收 集 器, 又 是 并 行 的 多 线 程 收 集 器……Parallel Scavenge 收 集 器 的 特 点 是 它 的 关 注 点 与 其 他 收 集 器 不 同, CMS 等 收 集 器 的 关 注 点 是 尽 可 能 地 缩 短 垃 圾 收 集 时 用 户 线 程 的 停 顿 时 间, 而 Parallel Scavenge 收 集 器 的 目 标 则 是 达 到 一 个 可 控 制 的 吞 吐 量( Throughput)。
serial Old收集器
Serial Old 是 Serial 收 集 器 的 老 年 代 版 本, 它 同 样 是 一 个 单 线 程 收 集 器, 使 用“ 标 记-整 理” 算 法。 这 个 收 集 器 的 主 要 意 义 也 是 在 于 给 Client 模 式 下 的 虚 拟 机 使 用。 如 果 在 Server 模 式 下, 那 么 它 主 要 还 有 两 大 用 途:
- 一 种 用 途 是 在 JDK 1.5 以 及 之 前 的 版 本 中 与 Parallel Scavenge 收 集 器 搭 配 使 用[ 1],
- 另 一 种 用 途 就 是 作 为 CMS 收 集 器 的 后 备 预 案, 在 并 发 收 集 发 生 Concurrent Mode Failure 时 使 用。
Parallel Old收集器
-Parallel Old 是 Parallel Scavenge 收 集 器 的 老 年 代 版 本, 使 用 多 线 程 和“ 标 记-整 理” 算 法。过 Parallel Scavenge 收 集 器 无 法 与 CMS 收 集 器 配 合 工 作
CMS收集器
- CMS( Concurrent Mark Sweep) 收 集 器 是 一 种 以 获 取 最 短 回 收 停 顿 时 间 为 目 标 的 收 集 器。
- 从 名 字( 包 含" Mark Sweep") 上 就 可 以 看 出, CMS 收 集 器 是 基 于“ 标 记— 清 除” 算 法 实 现 的, 它 的 运 作 过 程 相 对 于 前 面 几 种 收 集 器 来 说 更 复 杂 一 些, 整 个 过 程 分 为 4 个 步 骤, 包 括:
- 初 始 标 记( CMS initial mark)
- 并 发 标 记( CMS concurrent mark)
- 重 新 标 记( CMS remark)
- 并 发 清 除( CMS concurrent sweep)
G1收集器
- G1 是 一 款 面 向 服 务 端 应 用 的 垃 圾 收 集 器
- G1 收 集 器 仍 然 可 以 通 过 并 发 的 方 式 让 Java 程 序 继 续 执 行。 -分 代 收 集: 与 其 他 收 集 器 一 样, 分 代 概 念 在 G1 中 依 然 得 以 保 留。 虽 然 G1 可 以 不 需 要 其 他 收 集 器 配 合 就 能 独 立 管 理 整 个 GC 堆, 但 它 能 够 采 用 不 同 的 方 式 去 处 理 新 创 建 的 对 象 和 已 经 存 活 了 一 段 时 间、 熬 过 多 次 GC 的 旧 对 象 以 获 取 更 好 的 收 集 效 果。
- 空 间 整 合: 与 CMS 的“ 标 记— 清 理” 算 法 不 同, G1 从 整 体 来 看 是 基 于“ 标 记— 整 理” 算 法 实 现 的 收 集 器, 从 局 部( 两 个 Region 之 间) 上 来 看 是 基 于“ 复 制” 算 法 实 现 的, 但 无 论 如 何, 这 两 种 算 法 都 意 味 着 G1 运 作 期 间 不 会 产 生 内 存 空 间 碎 片, 收 集 后 能 提 供 规 整 的 可 用 内 存。 这 种 特 性 有 利 于 程 序 长 时 间 运 行, 分 配 大 对 象 时 不 会 因 为 无 法 找 到 连 续 内 存 空 间 而 提 前 触 发 下 一 次 GC。
- 可 预 测 的 停 顿: 这 是 G1 相 对 于 CMS 的 另 一 大 优 势, 降 低 停 顿 时 间 是 G1 和 CMS 共 同 的 关 注 点, 但 G1 除 了 追 求 低 停 顿 外, 还 能 建 立 可 预 测 的 停 顿 时 间 模 型, 能 让 使 用 者 明 确 指 定 在 一 个 长 度 为 M 毫 秒 的 时 间 片 段 内, 消 耗 在 垃 圾 收 集 上 的 时 间 不 得 超 过 N 毫 秒, 这 几 乎 已 经 是 实 时 Java( RTSJ) 的 垃 圾 收 集 器 的 特 征 了。
- 如 果 不 计 算 维 护 Remembered Set 的 操 作, G1 收 集 器 的 运 作 大 致 可 划 分 为 以 下 几 个 步 骤:
- 初 始 标 记( Initial Marking)
- 并 发 标 记( Concurrent Marking)
- 最 终 标 记( Final Marking)
- 筛 选 回 收( Live Data Counting and Evacuation)
内存分配和回收策略
对象优先在Eden分配
- 大 多 数 情 况 下, 对 象 在 新 生 代 Eden 区 中 分 配
- 当 Eden 区 没 有 足 够 空 间 进 行 分 配 时, 虚 拟 机 将 发 起 一 次 Minor GC。
大对象直接进入老年代
- 所 谓 的 大 对 象 是 指, 需 要 大 量 连 续 内 存 空 间 的 Java 对 象, 最 典 型 的 大 对 象 就 是 那 种 很 长 的 字 符 串 以 及 数 组( 笔 者 列 出 的 例 子 中 的 byte[] 数 组 就 是 典 型 的 大 对 象)。
长期存活的对象直接进入老年代
- 既 然 虚 拟 机 采 用 了 分 代 收 集 的 思 想 来 管 理 内 存, 那 么 内 存 回 收 时 就 必 须 能 识 别 哪 些 对 象 应 放 在 新 生 代, 哪 些 对 象 应 放 在 老 年 代 中。 为 了 做 到 这 点, 虚 拟 机 给 每 个 对 象 定 义 了 一 个 对 象 年 龄( Age) 计 数 器
- 如 果 对 象 在 Eden 出 生 并 经 过 第 一 次 Minor GC 后 仍 然 存 活, 并 且 能 被 Survivor 容 纳 的 话, 将 被 移 动 到 Survivor 空 间 中, 并 且 对 象 年 龄 设 为 1。 对 象 在 Survivor 区 中 每“ 熬 过” 一 次 Minor GC, 年 龄 就 增 加 1 岁, 当 它 的 年 龄 增 加 到 一 定 程 度( 默 认 为 15 岁), 就 将 会 被 晋 升 到 老 年 代 中。
新 生 代 GC( Minor GC): 指 发 生 在 新 生 代 的 垃 圾 收 集 动 作, 因 为 Java 对 象 大 多 都 具 备 朝 生 夕 灭 的 特 性, 所 以 Minor GC 非 常 频 繁, 一 般 回 收 速 度 也 比 较 快。
老 年 代 GC( Major GC/ Full GC): 指 发 生 在 老 年 代 的 GC, 出 现 了 Major GC, 经 常 会 伴 随 至 少 一 次 的 Minor GC( 但 非 绝 对 的, 在 Parallel Scavenge 收 集 器 的 收 集 策 略 里 就 有 直 接 进 行 Major GC 的 策 略 选 择 过 程)。 Major GC 的 速 度 一 般 会 比 Minor GC 慢 10 倍 以 上。
Java设计模式笔记
Java设计模式
##01单例模式
单例模式保证一个类只有一个实例,并提供一个可以访问他的全局访问点。当系统需要某个类只能有一个实例时,就可以采用单例模式。
单例模式实现方式
- 直接实例化
public class Singleton{
private Singleton(){}
private static final Singleton single=new Singleton();
public static Singleton getInstance(){
return singleton;
}
}
- 延迟实例化
public class Singleton{
private Singleton(){}
private static Singleton singleton=null;
public static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
- 静态内部类
public class Singleton{
private static calss My{
private static final Singleton single=new Singleton();
}
private Singleton(){
System.out.println("this is new instance");
}
public static final Singleton getInstance(){
return My.single;
}
}
- 单例模式应用:日志文件、编辑配置文件单例信息类、sevelt、jsp
02工厂模式
当用户需要一个类的子类实例,且不希望与该类的子类形成耦合或者不知道该类有哪些子类可用时,可以使用工厂模式;当用户需要系统提供多个对象,且希望和创建对象的类解耦时,可采用抽象工厂模式。
- 简单工厂模式
//定义小汽车接口
public interface ICar{}
//高档小汽车
public class UpCar implements ICar{}
//中档小汽车
public class MidCar implements ICar{}
//低档小汽车
public class DnCar implements ICar{}
//简单工厂
public class CarSimpleFactory{
public static final String UPTYPE="uptype";
public static final String MIDTYPE="midtype";
public static final String DNTYPE="dntype";
public static ICar create(String mark){
ICar obj=null;
if(mark.equals(UPTYPE)){
obj=new UpCar();
}
if(mark.equals(MIDTYPE)){
obj=new MidCar();
}
if(mark.equals(ONTYPE)){
obj=new OnCar();
}
return obj;
}
}
- 抽象工厂模式
//定义小汽车接口
public interface ICar{}
//高档小汽车
public class UpCar implements ICar{}
//中档小汽车
public class MidCar implements ICar{}
//低档小汽车
public class DnCar implements ICar{}
//定义公共汽车接口
public interface IBus{}
//高档公共汽车
public class UpBus implements IBus{}
//中档公共汽车
public class MidBus implements IBus{}
//低档公共汽车
public class DnBus implements IBus{}
//定义抽象工厂
public abstract class AbstractFactory{
public abstract ICar create();
public abstract IBus create();
}
//定义高档工厂
public class UpFactory extends AbstracetFactory{
public ICar create(){
return new UpCar();
}
public IBus create(){
return new UpBus();
}
}
//定义高档工厂
public class MidFactory extends AbstracetFactory{
public ICar create(){
return new MidCar();
}
public IBus create(){
return new MidBus();
}
}
//定义中档工厂
public class DnFactory extends AbstracetFactory{
public ICar create(){
return new DnCar();
}
public IBus create(){
return new DnBus();
}
}
从本质上讲,抽象工厂与工厂模式一致,只不多抽象工厂是多产品系,而工厂模式是单产品模式。
应用:编写文件读写功能
03生成器模式(也叫建造者模式)
生成器模式是指将一个复杂对象与它的表示分离,使同样的构建过程可以创建不同的表示。适合该场景如下:对象结构复杂,利用构造方法创建对象无法满足用户需求;对象创建过程必须独立于创建该对象的类。
生成器模式编程步骤:
1、定义一个产品类
public class Unit{...}
public class Unit2{...}
public class Unit3{...}
public class Product{
Unit u;
Unit2 u2;
Unit3 u3;
}
2、 定义N个生成器Build类
//定义生成器类接口IBuild
public intgerface IBuild{
public void createUnit();
public void createUnit2();
public void createUnit3();
public Product composite();//返回值是Product对象
}
//定义3个生成器类
public class BuildProduct implements IBuild{//生成第1种Product
Product p=new Product();
public void createUnit(){
//p.u=...
}
public void createUnit2(){
//p.u2=...
}
public void createUnit3(){
//p.u3=...
}
public Product composite(){
return p;
}
}
public class BuildProduct2 implements IBuild{//生成第2种Product
Product p=new Product();
public void createUnit(){
//p.u=...
}
public void createUnit2(){
//p.u2=...
}
public void createUnit3(){
//p.u3=...
}
public Product composite(){
return p;
}
}
public class BuildProduct3 implements IBuild{//生成第3种Product
Product p=new Product();
public void createUnit(){
//p.u=...
}
public void createUnit2(){
//p.u2=...
}
public void createUnit3(){
//p.u3=...
}
public Product composite(){
return p;
}
}
3、定义一个统一调度类
pulic class Director{
private IBuild build;
public Director(IBuild build){
this.build=build;
}
public Product build(){
build.createUnit();
build.createUnit2();
build.createUnit3();
return build.composite();
}
public static void main(String[] args){
IBuild build=new IBuild();
Director direct=new Director();
Product product=direct.build();
}
}
对于生成器模式创建复杂的对象而言,主要原则是对象构建过程与表示相分离。将复杂对象需要的类用生成器类生成并组合,最后返回真正需要的对象,而业务类只需要用生成器类获得对象即可。
04原型模式
原型模式是指用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。适合原型模式的情景如下:程序需要从一个对象出发,得到若干个和其状态相同,并可独立变化其状态的对象时;对象创建需要独立于他的构造方法和表示时;以原型对象为基础,克隆新的对象,并完善对象实例变量时。
原型模式复制功能分为浅复制和深复制:
- 浅复制:原型中值类型成员变量直接复制,引用类型则将地址复制。
- 深复制:原型中不管值类型还是引用类型都复制一份。
学生基本信息类:
class Student{
String name;
int age;
Address add;
Student(String name,int age,Address add){
this.name=name
this.age=age;
this.add=add;
}
//省略getter\setter方法具体实现
getter;
setter;
}
class Address{
String pro;
String city;
String zip
public Address(String p,String c,String z){
pro=p;city=c;zip=z;
}
getter;
setter;
}
利用构造函数方法
(1) 浅复制
public class Student{
Student(Student s){
//省略代码学生基本信息类
name=s.getName();
age=s.getAge();
add=s.getAdd();
}
}
public class test{
Adress add=new Address("liangzehua","dalian","116081");
Student s=new Student("zhang",20,add);
Student s2=new Student(s);//以s为原型复制对象s2
Student s3=new Student(s);//以s为原型复制对象s3
}
(2) 深复制
class Address{
public Address(Adress add){
pro=add.getPro();
city=add.getCity();
zip=add.getZip();
}
}
Class Student{
Student (Student s){
name=s.getName();
age=s.getAge();
add=new Address(s.getAdd());
}
}
利用Cloneable方法
Object类提供一个clone方法,可以将一个Java对象复制一份,clone方法属于protected犯法,外部类不能直接调用,能够实现复制的Java类必须实现一个标识接口Clonable。
(1)浅复制
public class Student implements Cloneable{
//其他代码同上
protectd Object clone()throws CloneNotSupportedException{
return super.clone();
}
}
//测试类
public class Test{
public static void main(String[] args){
Address add=new Address("liaoning","dalian","116081");
Student s=new Student("zhang",20,add);
Student s2=(Student)s.clone();
}
}
(2)深复制
class Address implements Cloneable{
protected Object clone() throws CloneNotSupportedException{
Address add=(Address)super.clone();
return add;
}
}
class Student implements Cloneable{
protected Object clone() throws CloneNotSupportException{
Student s=(Student)super.clone();
s.setAdd((Address)add.clone));
return s;
}
}
//test类同上
利用Serializable序列化方法
class Address implements Serializable{
public Address(Adress add){
pro=add.getPro();
city=add.getCity();
zip=add.getZip();
}
}
class Student implements Clonable,Serializable{
protected Object clone() throws CloneNotSupportException{
Object obj=null;
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(this);
//从流里读回来
ByteArrayInputStream bis = new ByteArrayInputStream();
ObjectInputStream ois=new ObjectInputStream(bis);
ois.readObject();
}catch(Exception e){
e.printStackTrace();
}
return obj;
}
}
序列化技术实现复制对象原理:序列化将对象写到流,写到流中就是原有对象的一个复制,原对象仍然存在内存中。序列化复制不仅可以复制对象本身,还可以复制其引用的成员对象,因此通过序列化将对象写入到流中,再从流中读取出来可以实现深复制。
##责任链模式
责任链模式定义如下:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象可以处理他为止。适合场景:有许多对象可以处理用户的请求,应用程序可自动确定谁处理用户请求;希望在用户不必明确指定接收者的情况下,向多个接收者提交一个请求;程序希望动态定制可处理用户请求的对象集合。
//以请假为例,少于一天组长决定,多于一天少于两条主任决定,两天以上经理决定
//请求类
public class Request(){
int day;
Request(int day){
this.day=day;
}
}
//抽象处理者
public abstract class Handler{
private Handler next;
public void setNext(Handler next){
this.next=next;
}
public Handler getNext(){
return next;
}
}
//三个具体处理者类(组长,主任,经理)
public class ZuZhang() extends Handler{
static int limit=1;
public boolean hanle(Request req){
if(req.day<=limit){
System.out.println("ZuZhang agree the request");
return true;
}
return getNext.hanle(req);
}
}
public class ZhuRen() extends Handler{
static int limit=2;
public boolean hanle(Request req){
if(req.day<=limit){
System.out.println("ZhuRen agree the request");
return true;
}
return getNext.hanle(req);
}
}
public class JingLi() extends Handler{
public boolean hanle(Request req){
System.out.println("JingLi agree the request");
return true;
}
}
//生成责任链前后顺序关系类
public class MyChain{
private Handler one=new ZuZhang();
private Handler two=new ZhuRen();
private Handler three=new JingLi();
public void createChain(){
one.setNext(two);
two.setNext(three);
}
public void handle(Request req){
one.handle(req);
}
}
//简单测试类
public Test{
public static void main(String[] args){
Request req=new Request(1);
MyChain mc=new MyChain();
mc.createChain();
mc.handle(req);
}
}
##07命令模式
命令模式定义如下:将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。适合命令模式的情景如下;程序需要在不同的时刻指定、排列和执行请求;程序需要提供撤销操作;程序需要支持宏定义。
//抽象命令接口
interface ICommand{
public void sweep();
}
//命令接收者
class Student{
public void sweep(){
System.out.println("we are sweeping the floor");
}
}
//命令发送者
class Teacher implements ICommand{
private Student receiver=null;
public Teacher(Student receiver){
this.receiver=receiver;
}
public void sweep(){
receiver.sweep();
}
}
//命令请求者
class Invoke{
ICommand command;
public Invoke(ICommand command){
this.command=command;
}
public void execute(){
command.execute();
}
}
//测试类
public class Test{
public static void main(String[] args){
Student s=new Student();
Teacher t=new Teacher(s);
Invoke invoke=new Invoke(t);
invoke.execute();
}
}
07迭代器模式
迭代器模式定义如下:提供一种方法访问一个容器对象中的各个元素,而又不暴露该对象的内部细节,是一种只应用于容器对象遍历的设计模式。适合迭代器场景如下:遍历集合元素、不需要知道对象在集合中的存储方式;用户可以同时使用多个迭代器遍历一个集合。
//自定义迭代器模式
//抽象迭代器接口
public interface Iterator{
Object next();
boolean hasNext();
}
//聚合容器接口
public interface Collection{
public void add(Object o);
public Iterator iterator():
}
//自定义数组容器类
public class MyArrayList implements Collection{
private Object[] elementData;
private int size;
public MyArrayList(int size){
elementData=new Object[size];
this.size=0;
}
public void add(Object o){
if(this.size==elementData.length){
int newSize=size*2;//容器扩容,并拷贝原数据
elementData=Arrays.copyof(elementData,newSize);
}
elementData[size]=o;
size++;
}
public Object get(int size){
return elementData[size];
}
pulic Iterator iterator(){
return new ArrayListIterator();
}
private class ArrayListIterator implements Iterator{
private int currenIndex=0;
public boolean hasNext(){
if(currentIndex>=size) return false;
else return true;
}
public Object next(){
Object o=elementData[currentIndex];
currentIndex++;
return o;
}
}
}
08访问者模式
访问者模式定义如下:表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各个元素的前提下,定义作用于这些元素的新操作。适合访问者模式情景如下:想对集合中的对象增加一些新的操作;需要对集合中的对象将进行很多不同且不相关的操作,而又不想修改对象的类。
//定义抽象需求分析接口IShape
interface IShape{
float getArea();//明确的需求分析
float getLength();//明确的需求分析
Object accept(IVisitor v);//可扩展的需求分析
}
//定义具体功能实现类
class Triangle implements IShape{
float x1,y1,x2,y2,x3,y3;
public Triangle(float x1,float y1,float x2,float y2,float x3,float y3){
this.x1=x2;
..........
}
public float getDist(float u1,float v1,float u2 , float v2){
.....//求任意两点之间的距离
}
public float getArea(){}//求面积
public float getLength(){}//求周长
public Object accept(IVisitor v){
return v.visit(this);
}
}
//定义访问者接口
interface IVisitor{
Object visit(Triangle t);
}
//定义其他扩展需求
class Point{
float x,y;
}
class CenterVisitor implements IVisitor{
public Object visit(Triangle t){
Point pt=new Point();
pt.x=(t.x1+t.x2+t.x3)/3;
pt.y=(t.y1+t.y2+t.y3)/3;
return pt;
}
}
//simple test class
public class Test3{
public static void main(String[] args){
IVisitor v=new CenterVisitor();
Triangle t=new Triangle(0,0,2,0,0,2);
Point p=(Point)t.accept(v);
}
}
09中介者模式
中介者模式是指用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互。适合中介者模式的情景如下:许多对象以复杂的方式交互,所导致的依赖关系使系统难以维护;一个对象引用其他很多对象,导致难以复用该对象。
//租房者
public class Renter{
String NO;
String name;
Mediator me;
Renter(String N,String na,Mediator me){
No=N;name=na;this.me=me;
}
public String getNO(){
return NO;
}
public String getName(){
reutn name;
}
void receive(String msg){
.....
}
void send(String msg){
me.send(this,msg);
}
}
//出租者
public class Saler{
String NO;
String name;
Mediator me;
Saler(String N,String na,Mediator me){
NO=N;.....
}
getNO(){}
getName(){}
void receive(String msg){}
void send(String msg){
me.send(this,msg);
}
}
//房屋中介者
public class Mediator{
Map<String,Renter> m=new HashMap();
Map<String,Saler> m2=new HashMap();
void addRenter(Renter r){
m.put(r.getNO(),r);
}
void addSaler(Saler s){
m2.put(s.getNO(),s);
}
void send(Renter r,String msg){
....
Set<String> se=m2.keySet();
Iterator<String> it=se.iterator();
while(it.hasNext){
String key=it.next();
Saler sa=m2.get(key);
sa.receive(r.getNO()+rr.getName()+msg);
}
}
void send(RentSaler rs,String msg){
....
Set<String> se=m2.keySet();
Iterator<String> it=se.iterator();
while(it.hasNext){
String key=it.next();
Renter r=m.get(key);
r.receive(s.getNO()+s.getName()+msg);
}
}
}
//test
pulic class Test{
public static void main(String[] args){
Mediator me=new Mediator();
Renter r=new Renter("1000","li",me);
Saler s=new Saler("2000","sun",me);
Saler s2=new Saler("2001","sun2",me);
me.addRenter(r);
me.addSaler(s);me.addSaler(s);
r.send("I want to rent a house");
r.send("I want to sale a house");
}
}
10备忘录模式
备忘录模式指在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。适合备忘录模式情景如下:必须保存某对象在某一时刻的部分或全部状态信息,以便对象恢复到该时刻的运行状态;一个对象不想通过提供public权限的方法让其他对象得到自己的内部状态
//备忘录类
public class Memento implements Serializable{
private int pos;
pulibc int getPos(){
return pos;
}
public void setPos(int pos){
this.pos=pos;
}
}
//备忘录管理类
public class Caretaker{
File file;
String strPath;
Catetaker(){
strPath=this.getClass().getResources("/").getPath();
file=new File(strPath+"two/Mymeme.txt");
}
public Memento getMemento(){
Memento me=new Memento();
if(file.exists()){
try{
.....//获取备忘录信息
}catch(Exception e){e.printStackTrace();}
}
}
pulic void saveMemento(Memento me){//保存到备忘录
FileOutputStream fos=new FileOutputStream(strPath+"two/Mymeme.txt");
ObjectOutputStream outobj=new ObjectOutputStream(fos);
outobj.writeObject(me);
}
}
//原生者类
pulic class ReadTopic{
private long pos;
private String strPath;
private RandomAccessFile in;
public ReadTopic(){
strPath=this.getClass().getResource("/").getPath();
in=new RandomAccessFile(strPath);
}
public void restoreFormMe(Memento me){
pos=me.getPost();
in.seek(pos);
}
public Memento createMemento(){
pos=in.getFilePointer();
Memento me=new Memento();
me.setPos((int)pos);
return me;
}
public String getNextTopic(){
String s=null;
s=in.readLine();
return s;
}
}
//test
public class Test{
public static void main(String[] args){
ReadTopic rt=new ReadTopic();
Memento mt=new Memento();
Caretaker ct=new Caretaker();
Scanner sc=new Scanner(System.in);
System.out.println("从断点处计算嘛?");
String strMark=sc.nextLine();
if(strMark.equals")){
me=ct.getMemento();//获得备忘录对象
rd.restoreFormMe(me)//恢复原发者状态
}
do{
String tStrTopic =rd.getNextTopic();//做题目
....
}while(strMark.equals("y"));
me.rd.createMemento();//创建备忘录
rd.close();
ct.saveMemento(me0;//保存备忘录对象
}
}
11观察者模式
观察者模式定义如下:定义对象一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象更新时需要通知其他对象,但该对象又不希望和被通知的其他对象形成耦合;当某对象更新时,需要让其他对象也各自更新自己的数据,但该对象不知具体有多少对象需要更新数据。
//观察者接口IObserver
public interface IObserver{
public void refresh(String data);
}
//主题接口ISubject
public interface ISubject{
public void register(IObserver obs);//注册观察者
public void unregister(IObserver obs);//撤销观察者
public void notifyObservers();//通知所以观察者
}
//主题实现类
public class Subject implemnts ISubject{
private Vector<IObserver> vec = new Vector();//观察者维护向量
private String data;//主题中心数据
public String getData(){return data;}
public void setData(String data){
this.data=data;
}
public void register(IObserver obs){
vec.add(obs);
}
public void unregister(IObserver obs){
if(vec.contains(obs)){
vec.remove(obs);
}
}
public void notifyObservers(){
for(int i=0;i<vec.size;i++){
IObserver obs=vec.get(i);
obs.refresh(data);
}
}
}
//一个具体的观察者类
public class Observer implements IObserver{
public void refresh(String data){
System.out.println("I have received thd data:"+data_);
}
}
//Test
public class Test{
public static void main(String [] args){
IObserver obs=new Observer();//定义观察者对象
IObserver obs2=new Observer();//定义观察者对象2
Subject subject=new Subject();//定义主题对象
subject.register(obs);//主题添加观察者
subject.register(obs2);
subject.setData("hello");//主题中心数据改变了
subject.notifyObservers();//通知所以观察者进行数据相应
}
}
12状态模式
运行一个对象在其内部状态改变时改变他的行为,使对象看起来似乎修改了它的类。适合场景:对象的行为依赖于它的状态,并且它必须在运行时根据状态改变他的行为;需要编写大量条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。
//定义状态抽象接口
interface IState{
public void goState();
}
//定义状态实现类
class ConcreteStateA implements IState{
public void goState(){
System.out.println("this is ConcreteStateA");
}
}
class ConcreteStateB implements IState{
public void goState(){
System.out.println("this is ConcreteStateB");
}
}
//定义状态上下文维护类
class Context{
private IState state;
public void setState(IState state){
this.state=state;
}
pulic void manage(){
//根据条件选择状态
state.goState();
}
}
策略模式
策略模式定义了一个共同的抽象算法接口,其子类实现了这个接口定义的方法,并且都有各自不同的实现,这些算法实现可以在客户端调用他们的时候互不影响变化。子类算法之间是弱关联的关系,因而提高了软件的可扩展性与可重用性。适合场景:上下文与具体策略是弱耦合关系;当增加新的具体策略时,不需要修改上下文代码,上下文可以引用新的具体策略的实例。
//抽象算法接口
public interface ICalc{
int calc(int a,int b);
}
//计算两个整数加法
public class AddCalc implements ICalc{
public int calc(int a,int b){
return a+b;
}
}
//计算两个整数减法
public class MinusCalc implements ICalc{
public int calc(int a,int b){
return a-b;
}
}
//计算两个整数乘法
public class MulCalc implements ICalc{
public int calc(int a,int b){
return a*b;
}
}
//计算两个整数除法
public class DivCalc implements ICalc{
public int calc(int a,int b){
return a/b;
}
}
//选择器功能
public class Select{
private ICalc obj;
public Select(ICalc obj){
this.obj=obj;
}
public int calc(int a,int b){
return obj.calc(a,b);
}
}
//test
public class Test{
public static void main(String [] args){
ICalc c=new AddCalc();
Select obj=new Select(c);
int result=obj.calc(1,2);
System.out.println("result:"+result);
}
}
14模板方法模式
模板方法模式是指定定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法可以不改变一个算法的结构,即可重定义该算法的某些特定步骤。适合场景:编制一个算法,将某些步骤的具体实现留给子类来实现;需要重构代码,将各个子类的公共行为提取到一个共同的父类中,避免代码重复。
public interface ILess<T>{
boolean less(T x,T y);
}
//泛型方法类
public class Algo<T> {
public T getMax(T t[],ILess<T> cmp){
T maxValue=t[0];
for(int i=1;i<t.length;i++){
if(cmp.less(maxValue,t[i]){
maxValue=t[i];
}
}
return maxValue;
}
}
//整型比较器
public class InteLess implements ILess<Integer>{
public boolean less(Integer x,Integer y){
return x<y;
}
}
//学生基本类
public class Student{
String name;
int grade;
public Student(String name,int grade){
this.name=name;
this.grade=grade;
}
}
//学生成绩比较类
public class StudentLess implements ILess<Student>{
public boolean less(Student x,Student y){
return x.grade<y.grade;
}
}
//Test
public class Test{
public static void main(String[] args){
Algo<Integer> obj=new Algo();
ILess<Integer> cmp=new InteLess();
Integer a[]={3,9,1,8};
Integer max=obj.getMax(a,cmp);
System.out.println("Integer max="+max);
Algo<Student> obj2=new Algo();
ILess<Student> cmp2=new InteLess();
Student s[]={new Student("li",70),new Student("sun",99)};
Student max2=obj2.getMax(s,cmp
System.out.println("Student max grade ="+max);
}
}
15享元模式
享元模式定义如下:运用共享技术有效的支持大量细粒度的对象。适合场景:对大量对象而言,许多属性相同,一旦创建则不能修改;对象的多数状态都可变为外部状态。他使用共享技术,用来尽可能的减少内存使用量,适合用于大量对象只是重复,常见做法是将他们放到外部数据结构,当使用时再传递给享元。
//定义抽象享元角色
public interface IFlyweight{
String getUniversity();
String getCity();
String getProvince();
}
//具体享元类Flyweight
public class Flyweight implements IFlyweight{
private String university;
private String city;
private String province;
public Flyweight(String u,String c,String p){
University=u;
...
}
getter();
}
//享元工厂类
public class FlyweightFactory{
private FleyweightFactory(){}
private static FlyweightFactory fact=new FlyweightFactory();
private Map<String,IFlyweight> map=new HashMap();
public synchronized static FlyweightFactory getInstance(){
return fact;
}
public void addFlyweight(String key,IFlyweight fly){
map.put(key,fly);
}
public synchronized IFlyweight getFlyWeight(String key){
IFlyweight obj=map.get(key);
return obj;
}
}
//学生基本信息类
public class StudInfo{
private String name;
private int age;
private IFlyweight fly;
public StudInfo(String n,int a,IFlyweight f){
name=n;
....
}
public void display(){
System.out.println("name="+name);
....
}
}
//Test
public class Test{
public static void main(String[] args){
FlyweightFactory fact=new FlyweightFactory.getInstance();
IFlyweight fly=new IFlyweight("LNNU","DALIAN","LIAONING");
IFlyweight fly2=new IFlyweight("JIDA","CHIANGHUN","JILIN");
fact.addFlyweight("one",fly);//想享元工厂添加享元对象
fact.addFlyweight("two",fly2);
IFlyweight obj=null;
obj=fact.getFlyweight("one");//从享元工厂获取享元对象
StudInfo s-new StudInfo("zhang",20,obj);
obj=fact.getFlyweight("two");
StudInfo s2-new StudInfo("Li",20,obj);
s.display();
s2.display();
}
}
16适配器模式
适配器模式定义如下:将一个类接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适合场景:一个程序想使用已存在的类,但该类实现的接口与当前程序所使用的接口不一致。
public interface IMath{
int add(int a,int b);
}
pulic class ThirdCompany{
public int addCalc(int a,int b){
return a+b;
}
}
public class MyMath implements IMath{
ThirdCompany third;
public MyMath(ThirdCompany third){
this.third=third;
}
public int add(int a,int b){
return third.addCalc(a,b);
}
}
//Test
pbulic class Test{
public static void main(String[] args){
ThirdCompany third=ThirdCompany();
IMath obj=new MyMath();
int v=obj.add(1,2);
System.out.println(v);
}
}
17代理模式
代理模式定义如下:为其他对象提供一组代理以控制对这个对象的访问。适合代理模式场景如下:不希望对象直接访问该对象,而是提供一个特殊对象以控制对当前对象的访问;如果要给对象需要很长时间才能加载完成;如果对象位于远程主机上,需要为用户提供远程访问能力。
interface ITV{
public void buyTV();
}
class Buyer implements ITV{
public void buyTV(){
System.out.println("i have bought the tv by proxy");
}
}
//定义代理
class BuyerProxy implements ITV{
private Buyer buyer;
public BuyerProxy(Buyer buyer){
this.buyer=buyer;
}
public void buyTV(){
preProcess();
buyer.buyTV();
postProcess();
}
public void preProcess(){
...
}
public void postProccess(){...}
}
18桥接模式
桥接模式定义如下:将抽象部分与他的实现部分分离,使他们都可以独立的变化。适合场景:不希望抽象和某些重要的实现代码是绑定关系,可运行时动态绑定;抽象和实现者都可以继承的方式独立地扩充,程序在运行时可能需要动态的将一个抽象子类的实例与一个实现者的子类实例进行组合,希望对实现者层次代码的修改对抽象层不产生影响,反之亦然。
//定义邮寄接口
public interface IPost{
public void post();
}
//平信邮寄类
pulic SimplePost imlements IPost{
public void post(){
System.out.println("this is Simple post");
}
}
//挂号邮寄类
class MarkPost implement IPost{
public void post(){
System.out.println("this is Mark post");
}
}
//抽象事物类
abstract class AbstractThing{
private IPost obj;
public AbstractThing(IPost obj){this.obj=obj}
public void post(){
obj.post();
}
}
//具体事物类
//信件类
class Letter extends AbstractThing{
public Letter(IPost obj){
super(obj);
}
}
//包裹类
class Parcel extends AbstractThing{
public Parcel(IPost obj){
super(obj);
}
}
//通过abstractThing 类中的成员变量obj,他就像桥梁一样,使得事物类与功能类巧妙的结合
//test
public class Test{
public static void main(Stirng[] args){
IPost p=new SimplePost();
Letter letter=new Letter(p);
letter.post();
}
}
装饰器模式
装饰器模式定义如下:动态的给对象添加一些额外的职责。就功能来说,装饰器模式相对比生成子类更为灵活。适合场景:程序希望动态的增强某个对象的功能,而又不影响该类的其他对象。
interface ILogger{
void log(String msg);
}
class ConsoleLogger implements ILogger{
public void log(String msg){
//控制台形式保存文件
System.out.println(msg);
}
}
class FileLogger implements ILogger{
public void log(String msg){
//文件形式保存日志
}
}
//抽象装饰器
abstract class Decorator implements ILogger{
protected ILogger logger;
public Decorator(ILogger logger){
this.logger=logger;
}
}
//信息大写装饰类
class UpLogger extends Decorator{
public UpLogger(ILogger logger){
super(logger);
}
public void log(String msg){
msg=msg.toUpperCase();
logger.log(msg);
}
}
//XML格式化装饰类
class XMLLogger extends Decorator{
public XMLLogger(ILogger logger){
super(logger);
}
public void log(String msg){
String s="<msg>"+
"<content>"+msg+"</content>"+
"</msg>";
logger.log(msg);
}
}
//Test
public class Test{
public static void main(String[] args){
ILogger existobj=new FileLogger();
ILogger newobj=new XMLLogger(existobj);
String s[]={"how","are","you"};
for(int i=0;i<s.length;i++){
newobj.log(s[i]);
thread.sleep(1000);
}
System.out.println("End");
}
}
19外观模式
外观模式是指为系统中的一组接口提供一个一致的界面,通过定义的一个高层接口,使得这一子系统更加容易使用。适合外观模式情景:对于一个复杂的子系统,提供一个便利的交互操作;不希望客户代码和子类中的类耦合。
class Container{//冰箱冷藏功能类
public void init(){
//init
}
public void run(){//冰箱运行}
public void shutdown(){//冰箱关机}
}
class Freezer{//冰箱冷冻功能类
public void init(){
//init
}
public void run(){//冰箱运行}
public void shutdown(){//冰箱关机}
}
class Refrigerator{//外观类
Container c=new Container();
Freezer f=new Freezer();
public void init(){
c.init;
f.init;
}
public void run(){
c.run;
f.run;
}
public shutdown(){
c.shutdown;
f.shutdown;
}
}
//用户只需要指导冰箱,不需要知道冷藏室和冷冻室,也不要要知道他们的开关机。
public class Test{
public static void main(String[] args){
Refrigerator r=new Refrigerator();
r.init();
r.run();
r.shutdown();
}
}
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.