· 设计模式
本课程是作为 Enterprise JavaBeans 开发的入门课程。主要目的是让您掌握开始编写 EJB 所需的知识。本教程涵盖了 EJB 的基本知识,如何编写无状态 (stateless) 和有状态(stateful)会话 bean,以及 CMP 和 BMP 类型的实体 bean。我们将采用 EJB 开发的最佳工具 VisualAge for Java 企业版来完成开发和布署 EJB 到 WebSphere 应用服务器高级版中。本教程不是要详细地讲解服务器端 EJB 运行的内部细节。本教程的关注是在于给学生提供必要的信息来进行开发。至于 EJB 容器和服务器是如何实现的则与本教程无关。在完成本教程后,您应该具有足够的知识来进行 EJB 开发了。本教程没有讨论 EJB 的安全(与其容器的实现相关),简单地介绍了事务处理概念(我们将有专门的文章来解释 EJB 的事务处理概念)。我们也介绍 EJB 开发常用的一些设计思想。
本章讲述内容
- 什么是一个模式?
- 如何有效使用 EJB 的模式
什么是一个模式?
- 在一个特定环境下对一个问题的解决方案
- 用文本和图表以结构化的方式表现设计思想
- 交换设计思想的一种方法
- 显示何时和如何应用解决方案
- 是面向对象设计领域最热门的方向
为何使用模式?
- 对常见问题的实用解决方案
- 设计人员的常用术语
- 对现存框架的文档描述
- 一旦被吸收后,好的设计思想变得非常的自然
- 可以组合起来设计出复杂的方案
减少远程方法调用
- 远程方法调用开销很大
- 尽量在 create 方法中设置状态
| ... Employee employee = employeeHome.create(); employee.setName("Wayne Beaton"); employee.setEmail("[email protected]"); employee.setPhone("613-555-6754"); ... |
一个远程调用方法
| ... employeeHome.create( "Wayne Beaton", "[email protected]", "613-555-6754"); ... |
· Proxy 模式...
- Proxy 被用来"替换"实体 Bean
- 一个可序列化的对象--包含该 Bean 中数据的一个拷贝
| 四个远程方法调用 |
| ... Employee employee = employeeHome.findById(42); out.println(employee.getName()); out.println(employee.getEmail()); out.println(employee.getPhone()); ... |
| 两个远程方法调用 |
| ... EmployeeProxy employee = employeeHome.findById(42).getProxy(); out.println(employee.getName()); out.println(employee.getEmail()); out.println(employee.getPhone()); ... |
| EmployeeBean method public EmployeeProxy getProxy() { EmployeeProxy proxy = new EmployeeProxy(); proxy.setName(getName()); proxy.setEmail(getEmail()); proxy.setPhone(getPhone()); proxy.setBirthdate(getBirthdate()); proxy.setStreet(getAddress().getStreet()); proxy.setCity(getAddress().getCity()); proxy.setState(getAddress().getState()); proxy.setCode(getAddress().getCode()); ... return proxy; } |
避免循环引用
- 建议使用 Bean 间单向的引用
- 互相引用的 Bean 可能造成死锁
- 在 Bean 间的递归引用不再存在了
隐藏这些实体 Bean
不要将您的实体 Bean 直接暴露给客户端--使用一个会话 Bean 作为前端· 隐藏实体 Bean:自动事务处理
| 为每个 Bean 的方法产生一个事务处理 |
| 客户端方法 void transferFunds(Account to, Account from, double amount) throws RemoteException { account1.debit(from); // TX_REQUIRED Assumed account2.credit(to); // TX_REQUIRED Assumed } |
| 为 transferFunds 方法创建一个事务处理 |
| TellerBean(会话 Bean)方法 void transferFunds(Account to, Account from, double amount) throws RemoteException { account1.debit(from); // TX_REQUIRED Assumed account2.credit(to); // TX_REQUIRED Assumed } |
隐藏实体 Bean: Loose Coupling
- 层次化的架构
- 客户端不知道您在使用实体 Bean
- 以后可以更换为其它技术,对客户端影响最小
- 层次化架构无论对有无分布式对象和EJB都是有效的
- 减少网络流量--使用 Proxy 对象在本地代表服务器端对象
Facade 模式...
- Facade 提供进入您的系统的一个入口点
- 由实体 Bean 提供的功能被隐藏起来
- 它将调用功能,而不是实现功能
- Facade 是一个会话 Bean (有状态或无状态)
- 幕后的 Bean 不会被暴露给客户端
| ... Teller facade = tellerHome.create(); facade.transferFunds(1234, 564, 2000.0); ... |
| TellerBean method void transferFunds(int toId, int fromId, double amount) throws FinderException, RemoteException { Account to = accountHome.findById(toId); Account from = accountHome.findById(fromId); account1.debit(from); account2.credit(to); } |
· Command 模式...
- Command 处理器的参数为 command 对象
- 很容易扩展
- 非常容易添加新的"command"类
- processCommand() 方法将 command 从客户端传递到服务器
...
TransferCommand command = new TransferCommand();
command.setFromAccount(1234);
command.setToAccount(543);
command.setAmount(1000.0);
Teller teller = tellerHome.create();
teller.processCommand(command);
... - 使用多态来执行 command
- 形成一个非常容易扩展的框架
- command 运行在服务器上
TellerBean method
CommandResult processCommand(Command command) {
try {
return command.process(getCommandContext());
} catch (Exception e) {
return new ResultFailure(...);
}
}
- 一个 command 上下文提供了执行上下文
例如,对系统资源的存取TransferCommand method
CommandResult process(CommandContext context) throws Exception {
Account toAccount = context.getAccountHome().findById(getToAccount());
Account fromAccount = context.getAccountHome().findById(getFromAccount());
toAccount.credit(amount);
fromAccount.debit(amount);
return new ResultSuccess();
}
本章讲述内容
- 模式描述了通用的可重复的解决方案
- 会话 Bean 可以(可能就应该)被用来在客户端和实体 Bean 间提供隔离
相关文章








