首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > Java > Session Facade 的规则和模式(2)
【标  题】:Session Facade 的规则和模式(2)
【关键字】:c,模式,io,Session,on,Session,Facade
【来  源】:网络

Session Facade 的规则和模式(2)

Session Facade 的规则和模式(2)

Session Facade 的重要规则

那么我们该如何应用这些关于针对会话的 Facade 的规则呢?这对我们的 EJB 设计又意味着什么呢?我在设计Session Facade 时遵循三条基本原则:

它们自己不做实际工作;它们委派其它对象做实际工作。这意味着Session facade 中的每个方法都应该很小(异常处理逻辑不计算在内,代码应为五行或更少)。
它们提供简单的接口。这意味着 facade 方法的数量应相对较少(每个Session bean 中仅有约 24 个)。
它们是底层系统的客户端接口。它们应该把特定于子系统的信息封装起来,并且不应该在不必要的情况下公开它。
那么它的工作机制呢?您还能代理别的哪些类型的对象呢?这又会给您的设计带来什么好处呢?在我的一篇早期论文和 [Brown 2001] 这本书中,我已论述了其中一些问题,在那里可以找到一些详细信息。但,总的来说,在我的多数 EJB 设计中我通常会找到以下四类对象:

值对象是包含了客户机所请求的数据的、可序列化的 Java bean。它包含Entity bean 和其他数据源所包含的数据的一个子集。它是Session EJB 方法的返回类型。[EJB 2.0] 和 [Sun 2001] 都描述了值对象和值对象的用途。请注意 [Fowler 2001] 称其为“数据传输对象”( Data Transfer Objects ),[Brown 1999] 也使用这个名称。我个人觉得数据传输对象是描述性更好的术语,但不幸的是,Sun 的术语似乎更通用。
对象制造厂 (Factory) [Brown 1999] [Brown 2000] 负责构建值对象。它能完成辨别不同的数据源、创建值对象的实例、填充值对象的实例等等工作。每个 factory 类 都可以从多个数据源中检索数据或更新其中的数据。在您的对象模型中,每个“根”对象都应该有一个 factory 类。(根对象是那些“包含”其它对象的对象。)从某种意义上说,对象 Factory 类在 JDBC 或持久的 Entity bean 子系统上担当 Facade,实现 [Gamma] 中提到的分层原则。
Entity EJB 应该是标准的、企业全局范围内可用的“数据源”。Entity bean 不应包含特定于应用程序的域逻辑,也不应限制为只能在单一应用程序内工作。请注意Entity bean 是可选的,它不是这种体系结构中必需的部分;Factory 可能像 JMS 队列或 JDBC 连接那样简单地直接从数据源获取数据。
Action 对象是Session bean 可能调用的唯一对商业业务进行处理的对象。Action 对象只处理与简单的创建、读取、更新或删除数据无关的商业流程。和对象 Factory 一样,Action 对象也充当内层 Facade。
一个 EJB 对象示例

描述类似这样的模式遇到的一个问题是,能够使用这种模式的示例都太大,以至于无法包含在模式自身的描述中。尽管如此,我还是要尝试举出如下示例(它显然很简单)来说明一下这些对象看起来是什么样子。

假设我们正在为银行构建一个 ATM 系统。这是最老掉牙的 OO 设计问题之一,当然其它很多书籍和论文已经讨论过它,但它确实有足够符合我们要求的有趣特点。通过分析,我们发现了两种 EJB。

从 ATM 到银行的连接表示为Session bean。该 bean 上有一些方法负责处理您通过 ATM 可以完成的交易 ? 存款、取款以及帐户间的资金转移。
帐户表示为Entity bean(我们的示例采用 CMP,但它在我们的示例中实际上并没什么影响)表示。它有返回帐户余额、对帐户进行借贷处理的方法。
ATM Session bean 的远程接口如下:

package com.ibm.bankexample.ejbs;

import com.ibm.bankexample.domain.*;

/**
* This is the Enterprise Java Bean Remote Interface
* for the ATM example.
*/
public interface ATM extends javax.ejb.EJBObject {

void deposit(java.lang.String accountNumber, double amount)
throws java.rmi.RemoteException,
com.ibm.bankexample.domain.FactoryException;

java.util.Vector getAccounts(java.lang.String userid)
throws java.rmi.RemoteException,
com.ibm.bankexample.domain.FactoryException;

void transfer(java.lang.String fromAccount, java.lang.String toAccount, double amount)
throws java.rmi.RemoteException,
com.ibm.bankexample.domain.InsufficientFundsException,
com.ibm.bankexample.domain.FactoryException;

void withdraw(java.lang.String accountNumber, double amount)
throws java.rmi.RemoteException,
com.ibm.bankexample.domain.InsufficientFundsException,
com.ibm.bankexample.domain.FactoryException;

}
同样地,帐户 EJB 的远程接口如下:

package com.ibm.bankexample.ejbs;

/**
* This is the Enterprise Java Bean Remote Interface
* for the Account Entity EJB.
*/
public interface Account extends javax.ejb.EJBObject {

void deposit(double amount) throws java.rmi.RemoteException;

java.lang.String getAccountNumber() throws java.rmi.RemoteException;

double getBalance() throws java.rmi.RemoteException;

java.lang.String getUserid() throws java.rmi.RemoteException;

void setBalance(double newValue) throws java.rmi.RemoteException;

void setUserid(java.lang.String newUserid) throws java.rmi.RemoteException;

void withdraw(double amount) throws java.rmi.RemoteException;

}
现在,我们还发现有另外两种对象类型对我们的系统是有用的。第一种是描述显示在 ATM 机上的帐户信息的值对象。这个类看起来如下所示:

public class AccountValue implements java.io.Serializable {
private java.lang.String accountNumber;
private double balance;
}
当然,AccountValue 类也有作为属性的 getter 和 setter 的方法,但我们暂时不考虑它们。

现在,我们基本上有了足够的信息来理解 ATM EJB 的 getAccounts() 方法的实现。这个方法的实现如下:

public java.util.Vector getAccounts(String userid) throws FactoryException {
AccountFactory fact = new AccountFactory();
Vector result = fact.getAccounts(userid);
return result;
}
这个方法展示了Session Facade EJB 的方法的标准模式。它找到合适的帮助对象(Action 或 Factory,在本例中是 Factory),调用帮助对象上的业务方法,然后返回结果。

如这个方法所指出的,我们需要一个 AccountFactory 类来从 Accounts 构建 AccountValues。这个类的类定义如下:

public class AccountFactory {
private static AccountHome accountHome = null;
}
AccountFactory 的 getAccounts(userid) 方法的实现如下:

public java.util.Vector getAccounts(String userid) throws FactoryException {
try {
Vector vect = new Vector();
AccountHome home = getAccountHome();
Enumeration accountRefs = home.findByUserid(userid);
while (accountRefs.hasMoreElements()) {
Account acc = (Account) accountRefs.nextElement();
AccountValue valueObject = new AccountValue();
valueObject.setAccountNumber(
acc.getAccountNumber());
valueObject.setBalance(acc.getBalance());
vect.addElement(valueObject);
}
return vect;
} catch (Exception e) {
throw new FactoryException(
"Cannot generate accounts due to wrapped exception " + e);
}
}
这个方法使用一个高速缓存的 AccountHome 实例,它是从以下方法中获取的:

private AccountHome getAccountHome() {
if (accountHome == null) {
try {
java.lang.Object homeObject = getInitialContext().lookup(
"com/ibm/bankexample/ejbs/Account");
accountHome =
(AccountHome) javax.rmi.PortableRemoteObject.narrow(
(org.omg.CORBA.Object) homeObject,
AccountHome.class);
} catch (Exception e) {
// Error getting the home interface
System.out.println(
"Exception " + e + " in createTimeSheetHome()");
}
}
return accountHome;

}
正如 [Brown 2001] 和 [Gunther 2000] 所描述的那样,在 WebSphere® 中,高速缓存 EJB home 是一个极好的习惯,因为获取 JNDI InitialContext 和从 InitialContext 获取 EJB Home 需要一段时间。

既然您已经看到了Session、Entity和 Factory 如何组合在一起,那我们就来看一个 Action 类的示例。在本例中,我们有一个处理从一个帐户到另一个帐户的资金转移的 Transfer 对象。Transfer 由 ATM EJB 中的 transfer() 方法的实现中创建,该方法的实现如下:

public void transfer(String fromAccount, String toAccount, double amount)
throws InsufficientFundsException, FactoryException {
Transfer trans = new Transfer();
trans.transfer(fromAccount, toAccount, amount);
}
请再次注意同样的流程。不过,这个方法不必从 Action 对象返回值。Transfer 类的定义如下:

public class Transfer {
private static AccountHome accountHome;
}
transfer() 方法的实现如下:

public void transfer(String fromAccount, String toAccount,
double amount) throws InsufficientFundsException, FactoryException {
try {
Account from = getAccountHome().findByPrimaryKey(
new AccountKey(fromAccount));
Account to = getAccountHome().findByPrimaryKey(
new AccountKey(toAccount));
if (from.getBalance() < amount)
throw new InsufficientFundsException();
to.deposit(amount);
from.withdraw(amount);
} catch (Exception e) {
throw new FactoryException(
"cannot perform transfer. Nested exception is " + e);
}
}
您已经看到,Transfer 对象中的 transfer() 方法处理以下细节:定位两个 Account 实体,确保“From”帐户有足够的余额,把转移金额存入“To”帐户,从“From”帐户中提出转移金额。同样地,您可以看到 Action 对象的其它方法可以实现您系统中的其它业务规则。
(未完待续)
Session Facade 的规则和模式(3):【上一篇】
Session Facade 的规则和模式(1):【下一篇】
【相关文章】
  • 设计模式在EJB中的应用(1)
  • 设计模式在EJB中的应用(2)
  • 设计模式在EJB中的应用(3)
  • 设计模式在EJB中的应用(4)
  • JSP设计模式
  • DAO及factory示例
  • JAVA和C++区别
  • 用JDBC开发基于客户/服务器模式的Internet/Intranet数据库软件(2)
  • J2EE设计模式浅谈(1)
  • J2EE设计模式浅谈(2)
  • 【随机文章】
  • 天堂2 亚丁版-三级血盟升四级血盟所必须过之血盟任务
  • DDoS的攻击原理与防御方法
  • 一个不错的网页设计器Iron Speed Designer,感兴趣的朋友研究一下吧……
  • coolfly教程-破解入门第七集
  • j2me游戏引擎——游戏引擎的基本构
  • 新狐传真群发2.0注册算法分析
  • 常用Linux Shell技巧集锦(不断更新中……)
  • 如何使用XQI?
  • 怎样做一名“专业”的程序员?
  • CSDN blog 添加音乐和天气预报效果
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 软讯网络 All Rigths Reserved.