当前位置: 首页 > 学习 > 电脑学习 > 程序设计 > JAVA > 设计模式 > 正文

Session Facade 的规则和模式(2)

http://www.zk168.com.cn  招考学习网 2006-4-11 3:37:24
-----------------------------------------------------------[交流]-[打印]-[发送]-[收藏]--
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 对象的其它方法可以实现您系统中的其它业务规则。
(未完待续)
-----------------------------------------------------------[交流]-[打印]-[发送]-[收藏]--
最新入库:
 
·实质、过程及意义——阿多尔诺“否定的辩证法”探微
·从Ontology的译名之争看哲学术语的翻译原则
·论马克思主义哲学经典的解释——解释学方法及其在马克
·中国哲学当前的核心与周边问题
·和合学与21世纪文化价值和科技
·中国文化的和合精神与21世纪
·宗教之间理当相互宽容
·上半个世纪的自由主义
·殷周至春秋时期神人关系之演进
·大学之道:构建以“三纲八目”为核心的道德修养体系
相关内容:
 
·环保企业人力资源开发与管理的实证研究————巨龙公
·21世纪以煤和天然气为原料的C1化学
·重油制气污水处理系统(A/O)技术改造
·OECD主要国家软件业发展概况
·英美CPA管理模式及其启示
·沙角C电厂事故顺序记录的通道组态分析及整改
·改造NERA微波公务信道为国产监控信道
·LFCB-102型微波分相差动保护的应用
·沙角C电厂厂用电结线分析
·EAStudio让电子商务网站如虎添翼
网友点评:
 
会员名称:
密码:匿名 ·注册·忘记密码?
评论内容:
(最多300个字符)
  查看评论
友情提醒:
 1.库中的资料大都来自互联网、网友上传、各类书籍,在录入的过程中难免会出现错误,恳请网
 友来信指正!
 2.如果网友在本库中未能找到所需要的材料,请登陆到我们的论坛《招考学习网》版块!
 3.考友想加入招考学习网的编辑部,请发信到XueXiWang#Gmail.com(#改为@)附带个人简历
 4.如需转载请注明出处及作者,谢谢合作!
 5.如果您有更好的建议或意见请EMAIL:XueXiWang#Gmail.com (#改为@)
 6.凡标题中有注有“[NO]”字样均不含答案且答案整理中.
 7.如本库中转载文章涉及版权等问题,请相关网站或作者在两周内发邮件通知(EMAIL:  XueXiWang#Gmail.com (#改为@))我们,我们接到通知后立即删除该文章及链接!
你问我答 更多>>