站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2EE 专题定制你的Java--根据应用剪裁JavaBeans

定制你的Java--根据应用剪裁JavaBeans

摘要: 定制你的Java--根据应用剪裁JavaBeans
内容: 摘 要: 对 于 可 定 制 的 组 件(Components), 开 发 者 可 以 根 据 自 己 的 需 要 剪 裁。 可 定 制 的JavaBeans 中 有 应 用 程 序 开 发 者 可 以 修 改 的 属 性(Properties) ─ ─ 例 如, 改 变Beans 的 外 观 和/ 或 动 作。 本 文 将 介 绍 如 何 定 制JavaBeans。 我 们 将 讨 论 属 性、 读 取 器(getter) 和 设 置 器(setter) 方 法(Mothods), 绑 定(Bound) 和 约 束(Constrained) 属 性, 以 及 使 定 制 简 单 化 的 设 计 模 板(Design Pattern)。 然 后 介 绍 属 性 编 辑 器(Editors) 和 定 制 器(Customizers), 最 后 我 们 在 一 个 已 有 的JavaBeans 中 增 加 定 制 功 能。

可 定 制 的 组 件 有 更 大 的 应 用 范 围。 例 如, 对 于 一 个 电 子 表 格(Spreadsheets) Bean, 假 如 它 必 须 占 满 全 屏 幕、 与 你 的 应 用 程 序 颜 色 方 案 冲 突 或 者 只 能 以16 进 制 方 式 显 示 数 据, 不 管 它 在 其 他 方 面 的 功 能 有 多 出 色, 你 恐 怕 不 能 用 它。

JavaBeans 规 范 对 简 单 情 况 提 供 了 非 常 简 单 的 识 别、 修 改 属 性 的 特 征, 对 复 杂 的 情 况 提 供 了 扩 展。

本 文 将 研 究JavaBeans 的 定 制 接 口、 组 件 属 性、 以 及 如 何 编 写 你 的Beans 使 得 集 成 开 发 环 境(IDEs) 可 以 将 这 些 属 性 显 示 给 应 用 程 序 开 发 者。 我 们 还 将 讨 论 以 下 的 问 题: 绑 定 和 约 束 属 性, 它 们 可 以 方 便Beans 之 间 通 信 和 维 持 一 致 性; 定 制 器, 它 可 以 使 我 们 更 方 便 地 定 制;BeanBox 的 使 用, 它 是Sun 免 费 提 供 的JavaBeans 测 试 工 具。

什 么 是 定 制
软 件 组 件 是 通 用 的 功 能 和 数 据 模 块, 它 可 以 在 很 多 情 况 下 使 用, 软 件 组 件 的 定 制 是 很 重 要 的, 如 果 应 用 程 序 开 发 者 可 以 控 制 其 外 观 和 行 为, 它 才 能 在 很 多 应 用 程 序 中 得 到 应 用。 例 如, 如 果 一 个 按 钮 类 的 文 本 标 签 总 是“Button”, 与 之 相 关 的 动 作 总 是 重 启 计 算 机( 虽 然 在 一 些 操 作 系 统 中 这 可 能 是 最 有 用 的 工 具 之 一) 的 话, 那 它 是 没 有 多 大 用 处 的。

简 单 的 组 件, 如 按 钮 都 有 很 多 开 发 者 可 以 控 制 的 属 性, 其 中 包 括:

是 否 使 能

动 作

背 景 颜 色

文 本 颜 色

大 小

位 置

形 状

标 签 文 本

当 按 此 按 钮 时 播 放 的 声 音 文 件
复 杂 的 组 件 需 要 更 多 的 定 制。 定 制 一 个 远 程 数 据 库 连 接 可 能 从 可 用 的 服 务 器 列 表 中 进 行 选 择( 信 息 只 有 在 运 行 时 才 可 用)、 选 择 协 议( 同 上)、 指 定 用 户 名 和 密 码 和 设 置 通 过 防 火 墙 访 问。

Beans 的 属 性
一 般 说 来, 定 制 就 是 配 置Beans 的 内 部 状 态, 使 其 外 观 和 行 为 适 合 所 用 的 环 境。 这 些 内 部 状 态( 颜 色、 大 小 和 密 码 字 符 串 等) 在JavaBeans 规 范 里 称 为 属 性。Beans 中 的 属 性 可 以 用 称 为 访 问 器(Accessors) 的 方 法 读 取 和 修 改。 一 个 访 问 器 方 法 是 读 取 属 性 值 的getter 方 法, 或 者 是 修 改 属 性 值 的setter 方 法。 在 按 钮Beans 中 有String getLabel() 方 法, 它 返 回Beans 的 当 前 标 签, 有void setLabel(String newLabel) 方 法, 它 设 置Beans 的 当 前 标 签, 只 有getter 方 法 的 属 性 是 只 读 的。

为 什 么 不 简 单 地 访 问Beans 内 部 地 数 据 成 员, 直 接 读 取 和 修 改 它 们, 而 是 编 写 一 些 访 问 器 呢 ? 因 为 不 能 保 证 属 性 和Beans 内 部 的 成 员 数 据 直 接 对 应。 例 如,Beans 中 的 标 签 属 性 可 能 是 一 个AWT 标 签 对 象, 但 是 也 可 能 不 是。 标 签 文 本 可 能 来 自 数 据 库, 可 能 是 另 一 个Bean 的 标 签, 也 可 能 当 需 要 时 形 成 一 个 标 签。 访 问 器 方 法 是Beans 中 属 性 的 统 一 接 口, 它 隐 藏 了 属 性 的 实 现 细 节。 这 是 好 的 面 向 对 象 编 程 惯 例, 因 为 它 减 小 了 对 象 间 的 依 赖 和“ 耦 合”。

符 合JavaBeans 规 范 的 集 成 开 发 环 境 能 分 析Beans, 找 到 它 的 属 性, 同 时 它 还 能 给 每 种 属 性 创 建 直 观 的 显 示( 称 为 属 性 编 辑 器), 允 许 开 发 者 在 设 计 时 修 改 属 性。 当 开 发 者 将 一 个Bean 放 入 应 用 程 序 中 时, 集 成 开 发 环 境 在 面 板 上 画 出 此Bean, 然 后 显 示 属 性 表, 它 是Bean 所 有 属 性 的 简 单 列 表, 每 个 属 性 有 一 个 对 应 的 编 辑 器。 集 成 开 发 环 境 调 用 所 有 的getter 方 法, 将Bean 中 当 前 属 性 值 显 示 在 属 性 表。 当 开 发 者 修 改 属 性 表 中 的 属 性 时, 集 成 开 发 环 境 调 用 相 应 的setter 方 法, 更 新 所 选Bean 中 的 相 关 属 性。

对 低 等 到 中 等 复 杂 度 的Beans, 在 设 计 时 调 用setter 方 法 配 置 它 往 往 已 经 足 够。 为 了 支 持 复 杂Beans 更 高 程 度 的 定 制, 规 范 中 定 义 了 定 制 器(customizer) 类。 开 发 者 可 以 扩 充Beans, 这 就 为 实 现 任 何 类 型 的 定 制 打 开 了 方 便 之 门: 复 杂 的 颜 色 拾 取 器、 图 形 化 的 网 络 配 置 精 灵, 只 要 你 愿 意, 甚 至 可 以 编 写 一 个VRML 界 面。 实 际 上, 以 上 描 述 的 属 性 表 可 以 看 作 是 集 成 开 发 环 境 自 动 产 生 的 定 制 器。 这 种 模 式 在JavaBeans 框 架 中 是 常 见 的: 简 单 的 情 况( 在 这 种 情 况 下, 简 单 的 属 性 类 型 已 有 属 性 编 辑 器) 往 往 只 须 很 少 或 根 本 不 须 工 作, 但 是 其 中 隐 藏 着 对 复 杂 情 况 的 访 问 方 法。

如 何 使Beans 可 定 制
JavaBeans 框 架 使 创 建 有 可 定 制 属 性 的Beans 变 得 相 当 容 易。 大 部 分 情 况 下, 根 本 无 须 写 任 何 代 码。 这 是 因 为JavaBeans 规 范 定 义 了 命 名 约 定, 集 成 开 发 环 境 可 用 它 来 推 断 与 属 性 相 关 的 方 法。 规 范 中 将 这 种 约 定 称 作 设 计 模 板。 如 果 不 考 虑 语 义 原 则 的 话 则 很 简 单: 名 字、 返 回 值 和 参 数 类 型 决 定 了 属 性 的 名 字 和 类 型。 当 集 成 开 发 环 境 装 载Beans 时, 使 用JDK 1.1 reflection 机 制 检 查Beans 中 所 有 的 方 法, 寻 找 以get 和set 开 头 的 方 法, 然 后 将 属 性 加 入 到 属 性 表 中, 以 便 开 发 者 定 制Beans。

定 制Beans
我 们 可 以 看 一 个 具 体Bean 定 制 的 例 子: 扩 展 一 个 简 单 的BarChart Bean。 读 源 程 序 便 可 以 发 现:BarChart Bean 已 经 有 符 合 规 范 中 设 计 模 板 的 读 取 器 和 设 置 器 方 法 ─ ─void setPercent(int iPercent) 和int getPercent()。 换 句 话 说, 它 已 经 有 一 个 属 性:percent。 将BarChart Bean 装 载 入BeanBox 中 看 有 什 么 发 生。


图1 BeanBox 中 的Barchat

图 的 左 边 是 一 个 包 括 可 用Beans 的 面 板, 便 于 在BeanBox 中 放 置。 中 部 是BeanBox 本 身,BarChart 已 被 选 择, 而 右 边 是BarChart 的 属 性 列 表。 属 性 列 表 中 包 括 五 个 属 性: 前 景 和 背 景(Color 类 型)、 字 体(Font 类 型)、percent( 整 数) 和 名 字( 字 符 串)。 当BeanBox 装 载BarChart 时, 发 现int getPercent 和void setPercent(int iPercent) 方 法, 便 将percent 看 作 是Bean 的 一 个 属 性, 并 将 它 以 及 一 个 整 型 数 属 性 编 辑 器(percent 标 签 右 边 的 文 本 框) 加 入 到 属 性 表 中。 调 用getPercent() 函 数 填 充 属 性 编 辑 器 的 值( 本 例 中 值 为0)。 对 属 性 表 中 的 所 有 属 性 都 做 同 样 的 处 理。

BarChart 只 定 义 了percent 属 性, 那 其 它 属 性 是 从 哪 里 来 的 呢 ? 因 为BarChart 定 义 为:
public class BarChart extends Canvas implements Serializable。

BarChart 继 承 了java.awt.Canvas, 而 它 又 继 承 了java.awt.Component, 它 定 义 了Color getForeground(),void setForeground(Color) 等。 这 意 味 着, 如 果 你 定 义 一 个Bean 的 子 类, 你 便 巧 妙 地 得 到 一 个 包 括 父Bean 所 有 属 性 的 新Bean。

当 你 在BeanBox 的 属 性 表 中 修 改 属 性 时,Bean 马 上 就 被 更 新。 在percent 的 属 性 编 辑 器 中 输 入"62",BeanBox 便 做 出 相 应 的 反 应, 如 图2 所 示。


图2 62% 的BarChart

集 成 开 发 环 境( 本 例 为BeanBox), 检 测 到percent 属 性 编 辑 器 的 值 改 变, 便 调 用setPercent() 更 新BarChart 的percent。

如 果 你 的 应 用 程 序 正 好 需 要 一 个 蓝 色 背 景、 两 点 的 黑 色 边 框 和 对 选 择 百 分 比 填 充 红 色,25 乘150 的BarChart, 一 切 都 很 好。

好 在 我 们 有 此Bean 的 源 代 码, 我 们 可 以 增 加 一 些 新 属 性:Color 型fillColor、floodColor 和borderColor, 整 型borderWidth、barHeight 和barWidth。 作 为 例 子, 我 们 增 加floodColor() 访 问 器。 我 们 首 先 定 义 填 充 颜 色private Color fgColor_ = Color.red。 为 了 避 免 与java.awt.Component 的 前 景 和 背 景 属 性 相 混 淆, 我 们 更 名 为floodColor, 并 编 写 它 的 访 问 器:

private Color floodColor_ = Color.red;
public void setFloodColor(Color floodColor)
{
   floodColor_ = floodColor;
}

public Color getFloodColor()
{
   return floodColor_;
}

对 其 他 属 性 也 可 增 加 类 似 的 访 问 器, 这 就 形 成 了 一 个 灵 活 的 新Bean 的 新 类 文 件。

到 此,BarChart 就 是 可 定 制 的 了。 我 们 可 以 将 它 们 设 置 成 我 们 喜 欢 的 外 观, 如 图3 所 示。


图3 已 定 制 的BarChartBeans

我 们 可 以 看 到 四 个BarChart Beans, 每 个 用 不 同 的 颜 色 方 案 和 不 同 的 百 分 比 填 充 定 制。 对BarChart 类 增 加 了 几 个 方 法 便 可 给 应 用 程 序 开 发 者 提 供 极 大 的 灵 活 性。

当 属 性 的 类 型 是 内 建 的 类 型, 而 且 你 并 不 介 意 键 入 字 符 串 来 提 取 颜 色, 这 样 工 作 得 很 好。 但 是 当 属 性 的 类 型 为 自 定 义 类 型 时, 例 如BarChart 有direction 属 性 指 示BarChart 的 增 长 方 向, 合 理 的 值 为 上、 下、 左 和 右, 如 何 定 制 呢 ?

笨 的 方 法 是 让 用 户 键 入 整 数0-3 来 指 示 方 向。 在JavaBeans 规 范 中 明 智 的 方 法 是 编 写 自 己 的 属 性 编 辑 器。java.beans.PropertyEditor 接 口 和java.beans.PropertyEditorSupport 实 用 工 具 类 允 许Beans 开 发 者 对 于 以 上 描 述 的 自 定 义 类 型, 如 方 向 类 型 指 定 属 性 编 辑 器。 自 定 义 属 性 编 辑 器 甚 至 可 以 是 图 形 化 的:NetworkConfiguration Bean 可 能 有HostConnections 属 性, 它 可 以 用 鼠 标 在 服 务 器 之 间 画 出 连 接 的 方 式 来 配 置。

对 于 基 本 的 属 性 有 最 后 一 点 需 要 注 意。 有 的 属 性 可 能 定 义 为 值 的 数 组, 而 不 仅 仅 是 标 量, 这 些 属 性 就 是 索 引 属 性(Indexed Properties)。 它 与 标 量 属 性 相 比 在 访 问 器 方 法 方 面 是 不 同 的。 读 取 器 和 设 置 器 方 法 被 重 载。 可 以 以 单 个 元 素 的 方 式 访 问 属 性:

void setProperty(int index, TYPE value)
TYPE getProperty(int index)

或 者 一 次 整 个 数 组 的 方 式:

void setProperty(TYPE valueList[])
TYPE[] getProperty()

例 如 对 于Polygon3D Bean, 它 将 自 己 画 在 画 布(Canvas) 上, 可 以 单 独 地 访 问 它 的 点:

Point3D newPoint = new Point3D(0,25,0);
myPolygon.setPoint(2,newPoint); //Throws exception if <3 points
或 者 一 次 设 置 整 个 数 组:

Point3D p1 = new Point3D(0, 10, 0);
Point3D p2 = new Point3D(10, 1, 15);
Point3D p3 = new Point3D(15, 0, 25);
Point3D[] points = {p1, p2, p3};
myPolygon.setPoint(points);

绑 定 和 约 束 属 性
绑 定 和 约 束 让 人 听 起 来 感 到 痛 苦, 但 是 它 能 将 你 从 诸 如 当 一 个 属 性 改 变 时 更 新 相 关 的GUI 元 素 等 繁 杂 的 细 节 里 解 脱 出 来 轻 松 地 工 作。 同 时 它 还 能 帮 助 你 维 护Beans 之 间 的 一 致 性。 绑 定 属 性 是 一 种Bean 属 性, 当 它 的 值 改 变 时, 它 的 设 置 器 方 法 通 知 其 它 对 象( 称 为 监 听 器listeners), 使 其 它Beans 可 以 执 行 一 定 的 动 作。 约 束 属 性 与 绑 定 属 性 相 似, 除 了 监 听 器 可 以“ 否 决” 属 性 的 改 变。 为 了 理 解 如 何 使 用 这 种 属 性, 有 必 要 理 解 新 的JDK 1.1 的 事 件 处 理 结 构 的 基 本 原 理。

事 件 监 听 器
当 属 性 改 变 时,Java 组 件 用JDK 1.1 中 出 现 的 新 概 念, 事 件 监 听 器(Event Listeners) 接 口 通 知 其 它 组 件。 当 属 性 改 变 时, 其 对 象 创 建 一 个 包 括 属 性 信 息 的 事 件 对 象(Event Objects), 然 后 传 给 对 此 属 性 感 兴 趣 的 组 件。

在AWT 旧 的 事 件 模 型 中, 事 件 处 理 基 于 继 承: 为 了 捕 获 一 个 事 件 并 作 出 处 理, 你 必 须 建 立 一 个 已 经 处 理 这 个 事 件 的 父 类 的 子 类, 改 变 其 行 为。 这 使 得 难 于 创 建、 处 理 新 的 事 件 类 型。 事 件 监 听 器 方 法 基 于 事 件 集 中 处 理: 产 生 事 件 的 对 象 维 护 一 张 其 它 对 这 类 事 件 感 兴 趣 的 对 象 的 列 表, 当 事 件 发 生 时, 将 事 件 传 给 这 些 对 象。

事 件 监 听 器( 概 念 性) 的 例 子
我 们 举 参 议 员 的 例 子。


图4 事 件 监 听 器 示 例

在 图4 中, 考 虑 四 个 对 象( 记 者、 战 略 家、 助 手 和 狂 热 者), 他 们 都 想 知 道 参 议 员 的 薪 水 变 动( 薪 水 是 参 议 员 类 的 一 个 属 性)。 假 设 法 律 规 定, 参 议 员 对 感 兴 趣 的 人 必 须 通 知 其 薪 水 的 变 动。 参 议 员 提 供 一 个 事 件 监 听 器 注 册 方 法, 本 例 为void addSalaryListener(SalaryListener l)。 调 用 此 方 法 的 对 象 被 加 入 到 参 议 员 为 薪 水 变 动 事 件 而 维 护 的 监 听 器 列 表 中。 当 薪 水 变 动 时, 调 用setSalary() 方 法, 它 同 时 创 建 一 个 包 括 薪 水 变 动 量 的SalaryChangedEvent 对 象, 调 用 监 听 器 的void salaryChanged(SalaryChangedEvent event) 方 法 将 此 事 件 传 给 监 听 器。 对 此 事 件, 各 监 听 器 完 成 各 自 特 定 的 功 能。

薪 水 实 际 的 变 动 量 包 含 在 参 议 员 传 给 各 监 听 器 的SalaryChangedEvent 对 象 中, 我 们 可 以 从java.util.EventObject 创 建 包 含 参 议 员 薪 水 变 动 量 的 子 类:

//Encapsulates salary change
public class SalaryChangedEvent extends java.util.EventObject
{
double raiseAmount_;
void setRaiseAmount(double raiseAmount){
raiseAmount_ = raiseAmount;

}

// tc

}

下 面 我 们 定 义SalaryListener 接 口, 它 扩 展java.util.EventListener 处 理SalaryChangedEvent:

interface SalaryChangedListener extends java.util.EventListener
{
   void SalaryChanged(SalaryChangedEvent event);
}

以 下 所 有 的 类 可 以 实 现SalaryListener 接 口, 使 自 己 注 册 到 参 议 员 类 并 接 收SalaryChangedEvent。

class Crank extends Crackpot implements SalaryListener
{
//register interest in salary by adding self to senator&acute;s
//list of salary listeners
public void Crank(Senator senatorToHarass) {
//place myself on this senator&acute;s list of listeners.
senatorToHarass.addSalaryChangedListener(this);
}

//the senator calls this method when his/her salary property changes
public void SalaryChanged(SalaryChangedEvent event) {
double theRaise = event.getRaiseAmount();
//Ramble ad naueam
}
}

绑 定 属 性
理 解 事 件 监 听 器 后, 我 们 讨 论 如 何 应 用 到 绑 定 属 性 上。 在java.beans 中 定 义 了PropertyChangeListener 事 件 监 听 器 和PropertyChangeEvent 事 件 类 型, 处 理 绑 定 属 性 的 改 变 通 知。Bean 是 事 件 的 来 源( 参 议 员), 监 听 器 是 所 有 对 属 性( 薪 水) 感 兴 趣 的 对 象。 对 事 件 来 源 的 绑 定 属 性 感 兴 趣 的 对 象 实 现PropertyChangeListener 接 口, 因 而 成 为 监 听 器。PropertyChangeEvent 来 源 的 对 象( 例 如 参 议 员) 实 现 以 下 方 法:

void addPropertyChangeListener(PropertyChangeListener l)
void removePropertyChangeListener(PropertyChangeListener l)

因 而 使 此 属 性 变 成 绑 定 的。 所 有 绑 定 属 性( 如 薪 水) 的 设 置 器 方 法 负 责 创 建PropertyChangeEvent, 并 在 属 性 改 变 以 后 将 它 传 给 所 有 的 注 册 监 听 器。 这 是 比 参 议 员 例 子 中 更 常 用 的 方 案, 因 为 只 有 一 种PropertyChangeEvent 类 型, 而 不 是 每 个 特 定 的 属 性 都 有 一 种 类 型。

为 了 更 容 易 实 现,JavaSoft 开 发 组 一 个 线 程 安 全(thread-safe) 的 类, 叫 做java.beans.PropertyChangeSupport, 它 管 理PropertyChangeListeners 列 表, 并 负 责 传 送 事 件。 你 可 以 将PropertyChangeSupport 作 为 一 个 成 员 包 括 在 你 的 类 中, 然 后 在 你 的 设 置 器 方 法 中 使 用 它, 处 理 所 有 的 绑 定 属 性 改 变 的 通 知。

约 束 属 性
除 了(1) 属 性 在 通 知 所 有 监 听 器 之 后, 而 不 是 之 前 改 变,(2) 设 置 器 方 法 可 以 抛 出 一 个PropertyVetoException 异 常 来 否 决 建 议 的 改 变 以 外, 约 束 属 性 和 绑 定 属 性 是 完 全 一 样 的。 事 件 的 来 源 对 象 将PropertyChangeEvent 传 给 所 有 监 听 器, 通 知 它 们 对 属 性 建 议 的 改 变。 如 果 一 个 监 听 器 不 同 意 这 个 改 变, 它 抛 出 一 个PropertyVetoException 异 常, 这 样 事 件 来 源 对 象 便 不 改 变 属 性。 在 这 种 情 况 下, 设 置 器 方 法 稍 微 不 同:

void setProperty(TYPE property) throws PropertyVetoException

因 此, 约 束 属 性 的 接 口 是VetoableChangeListener, 而 不 是PropertyChangeListener。 使 处 理 更 容 易 的 支 持 类 是VetoableChangeSupport。

当 一 个 监 听 器 否 决 一 个 改 变 时, 会 引 起 另 一 个 问 题: 一 部 分 监 听 器 认 为 属 性 值 已 经 改 变( 因 为propertyChanged() 方 法 已 经 被 调 用), 而 另 一 本 分 则 认 为 没 有 改 变。 因 此, 此 时 设 置 器 方 法 必 须 回 过 头 来 重 新 通 知 所 有 已 被 通 知 的 监 听 器, 对 象 没 有 改 变 属 性 值。 一 般 说 来, 设 置 器 方 法 并 不 负 责 这 种“ 改 变 - 回 头” 通 知 否 决,VetoableChangeSupport 工 具 类 为 你 处 理 这 些 工 作, 除 非 有 十 分 充 分 的 理 由 自 己 去 实 现 它 以 外, 应 该 使 用VetoableChangeSupport。

约 束 属 性 的 例 子
为 了 使BarChart 类 更 智 能 化, 我 们 将Barchart Bean 的percent 属 性 与 另 外 一 个Bean 的 整 数 属 性 绑 定。percent 可 以 绑 定 到 任 何Beans 中 的 任 何 属 性 上, 只 要 它 能 传 送 包 含 整 数 的PropertyChangeEvent( 假 设 此 整 数 在0 和100 之 间),BarChart 就 会 忠 实 地 用 图 形 方 式 将 此 数 显 示 出 来。

首 先 我 们 必 须 将BarChart 类 设 计 成 事 件 监 听 器, 只 有 当 它 是 一 个PropertyChangeListener, 即 实 现java.beans.PropertyChangeListener 接 口, 才 能 接 收 到PropertyChangeEvent。 为 实 现 此 接 口, 一 个 类 只 用 实 现 一 个 方 法:public void propertyChange(PropertyChangeEvent event)。 事 件 来 源 对 象 改 变 属 性 时, 它 同 时 产 生PropertyChangeEvent, 并 且 传 给 所 有 的 监 听 器。PropertyChangeEvent 对 象 包 含 了 发 送 它 的 对 象 的 如 下 信 息: 被 改 变 属 性 的 名 字、 其 新 值 和 旧 值 以 及 以 什 么 对 象 存 储( 即 整 数 必 须 以Integer 对 象 存 储 等 等)。

为 了 使BarChart 成 为 一 个PropertyChangeListener, 我 们 加 入 一 个 接 口 并 且 实 现 它:

public class BarChartBean
   extends Canvas implements Serializable, PropertyChangeListener
{
   // Respond to a property change event for the property
   //"value" by updating my value to new value
   public void propertyChange(PropertyChangeEvent event)
   {
       Integer newValue = (Integer)event.getNewValue();
       setPercent(newValue.intValue());
   }
}

只 要 当BarChartBean 接 收 到 一 个PropertyChangeEvent, 便 读 取 其 新 值 并 且 赋 值 给percent 属 性。

我 们 需 要 一 个 给BarChart Bean 传 送 事 件 的 类。 以 下 创 建 一 个 称 为IntBox 的 简 单Bean, 它 是java.awt.TextField 的 子 类, 只 接 收 数 字 并 计 算 它 的 值。IntBox 有 一 个 特 点: 它 实 现 了 两 个 称 为public void addPropertyChangeListener(PropertyChangeListener listener) 和public void removePropertyChangeListener(PropertyChangeListener listener) 的 函 数。 实 现 了PropertyChangeListener 接 口 的 类( 例 如BarChart) 便 可 以 调 用 这 些 函 数, 将 自 己 加 入 或 者 移 出 监 听 来 自IntBox 的PropertyChangeEvents 的 类 的 列 表。 以 下 是 这 些 方 法 的 实 现:

public class IntBox extends TextField implements Serializable
{
   PropertyChangeSupport pcs_;    //constructor, etc
   //Allow other objects to register interest in my bound properties
   public void addPropertyChangeListener(PropertyChangeListener listener)
   {
       pcs_.addPropertyChangeListener(listener);
   }
   //Allow other objects to remove their interest in my bound properties
   public void removePropertyChangeListener(PropertyChangeListener listener
   {
       pcs_.removePropertyChangeListener(listener);
   }

实 用 工 具 类PropertyChangeSupport 为 你 维 护 列 表, 从 而 简 化 了 对 监 听 器 的 跟 踪。 当IntBox 的value 属 性 改 变 时( 即 当setValue() 被 调 用 时), 必 须 通 知 所 有 的 监 听 器。 我 们 在setValue() 中 加 入 额 外 的 一 行 来 创 建 和 传 送 事 件 对 象:

//Set new vaule
public void setValue(int value)
{
   int oldValue = prev_;
   setText(Integer.toString(value));
   int newValue = getValue();

   pcs_.firePropertyChange("value", new Integer(oldValue),
new Integer(newValue));
   prev_=newValue;
}

这 段 代 码 是 相 当 简 单 的, 我 们 读 取 新 值 后 调 用PropertyChangeSupport 对 象 中 的firePropertyChange() 方 法, 并 给 出 改 变 属 性 的 名 字、 旧 值 和 新 值。 然 后 跟 踪 旧 值 以 便 下 次 调 用 时 再 次 使 用 它。firePropertyChange() 方 法 创 建 一 个PropertyChangeEvent 对 象 并 且 将 它 传 给 所 有 的 监 听 器, 除 非 旧 值 和 新 值 相 等。PropertyChangeEvent 中 嵌 入 了 源 对 象 和 属 性 名, 以 便 监 听 器 根 据 谁 改 变 了 什 么 来 决 定 如 何 动 作。

合 二 为 一
我 创 建 了 一 个 称 为ColorBar 的 类, 它 包 括IntBox Bean 和BarChart Bean。 将 它 装 载 入BeanBox 便 可 以 看 到 它 的 动 作。ColorBar 在 其 构 造 器 中 创 建 了IntBox 和BarChart 组 件, 然 后 执 行:

intBox_.addPropertyChangeListener(barChartBean_);

这 是 关 键 之 处。BarChartBean 成 了 一 个PropertyChangeListener, 当IntBox 的 值 改 变 时, 它 便 是 监 听 器 中 的 一 员。 事 件 的 顺 序 很 简 单:

用 户 键 入 数 字 并 敲 回 车。

IntBox.processKeyEvent() 从 中 获 取 当 前 整 数 值 并 且 调 用setValue()。

IntBox.setValue() 更 新 属 性 值, 然 后 调 用firePropertyChange()。

firePropertyChange() 创 建PropertyChangeEvent 对 象 并 且 传 给BarChartBean 的propertyChanged()。

BarChartBean.propertyChanged() 设 置BarChartBean 的percent 值,BarChart 被 更 新。( 假 设 输 入 的 数 在0 到100 之 间)
在BeanBox 中 的 结 果 如 图5 所 示。


图5 绑 定 属 性 工 作 正 常

这 里 有 一 个 问 题:BarChart 只 接 收0 到100 之 间 的 输 入, 但 是IntBox 可 以 将 其value 属 性 设 置 为 任 意 的 正 整 数。 这 个 问 题 可 以 用 前 面 讨 论 过 的 约 束 属 性 解 决。 如 果BarChart 实 现VetoableChangeListener, 而IntBox 使 用VetoableChangeSupport 对 象, 则 当 值 超 出 范 围 时,BarChart 可 以 在propertyChanged() 中 抛 出 一 个 异 常,IntBox 便 被 禁 止 将 新 值 赋 值 给value。 只 有BarChart 接 受 的 数 才 是 允 许 的。

结 论
关 于 属 性 主 题 还 有 很 多 值 得 讨 论。 特 别 是, 因 为BeanBox 支 持PropertyChangeListener 接 口, 它 能 自 动 形 成 类, 将 一 个Bean 的 属 性 绑 定 到 另 一 个Bean 的 属 性 上。 你 可 以 试 试: 在BeanBox 中 装 入 一 个BarChartBean 和 一 个IntBox, 选 择IntBox, 然 后 在 菜 单 上 选 择Edit->Bind Property, 你 将 发 现 你 可 以 以 图 形 的 方 式 创 建ColorBar Bean。

以 上 我 们 讨 论 了 属 性 以 及 如 何 利 用 它 定 制Beans。 我 们 讨 论 了 事 件 监 听 器 接 口、 绑 定 属 性 和 约 束 属 性, 然 后 用PropertyChangeListener 接 口 将 一 个Bean 的 属 性 绑 定 到 另 一 个 的 属 性 上。


Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd, scwcd 摘 要:
↑返回目录
前一篇: 事件监听器?将JavaBeans接通起来的方法
后一篇: 最佳实践:有状态会话 bean运行结束时应及时被显式删除