EJB(Enterprise JavaBeans)入门(10) · 设计模式 本课程是作为 Enterprise JavaBeans 开发的入门课程。主要目的是让您掌握开始编写 EJB 所需的知识。本教程涵盖了 EJB 的基本知识,如何编写无状态 (stateless) 和有状态(stateful)会话 bean,以及 CMP 和 BMP 类型的实体 bean。我们将采用 EJB 开发的最佳工具 VisualAge for Java 企业版来完成开发和布署 EJB 到 WebSphere 应用服务器高级版中。本教程不是要详细地讲解服务器端 EJB 运行的内部细节。本教程的关注是在于给学生提供必要的信息来进行开发。至于 EJB 容器和服务器是如何实现的则与本教程无关。在完成本教程后,您应该具有足够的知识来进行 EJB 开发了。本教程没有讨论 EJB 的安全(与其容器的实现相关),简单地介绍了事务处理概念(我们将有专门的文章来解释 EJB 的事务处理概念)。我们也介绍 EJB 开发常用的一些设计思想。 本章讲述内容 什么是一个模式? - 在一个特定环境下对一个问题的解决方案
- 用文本和图表以结构化的方式表现设计思想
- 交换设计思想的一种方法
- 显示何时和如何应用解决方案
- 是面向对象设计领域最热门的方向
为何使用模式? - 对常见问题的实用解决方案
- 设计人员的常用术语
- 对现存框架的文档描述
- 一旦被吸收后,好的设计思想变得非常的自然
- 可以组合起来设计出复杂的方案
减少远程方法调用 - 远程方法调用开销很大
- 尽量在 create 方法中设置状态
... Employee employee = employeeHome.create(); employee.setName("Wayne Beaton"); employee.setEmail("wbeaton@ca.ibm.com"); employee.setPhone("613-555-6754"); ... | 一个远程调用方法 ... employeeHome.create( "Wayne Beaton", "wbeaton@ca.ibm.com", "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 间提供隔离
(全文完)
|