PetStore 中EJB 的设计模式[长]

PetStore 中EJB 的设计模式
1/1
目录..............................................................................................................................................1
PetStore 中EJB 的设计模式............................................................................................................3
1. 概述..........................................................................................................................................3
2. 模式分类..................................................................................................................................4
2.1. Data Access Object 模式..........................................................................................4
2.1.1. 意图...................................................................................................................4
2.1.2. 动机...................................................................................................................4
2.1.3. 结构...................................................................................................................5
2.1.4. PetStore 的例子................................................................................................6
2.1.4.1 概述...................................................................................................6
2.1.4.2 CatalogEJB................................................................................................8
2.1.4.3 CatalogDAO..............................................................................................9
2.1.4.4 CatalogDAOImpl ......................................................................................9
2.1.4.5 CatalogDAOFactory................................................................................10
2.1.5. GOF 模式关系................................................................................................10
2.1.4.6 Bridge 模式.............................................................................................10
2.1.4.7 Adapter 模式...........................................................................................11
2.2. Value Object 模式...................................................................................................11
2.2.1. 意图.................................................................................................................11
2.2.2. 动机.................................................................................................................13
2.2.3. 结构.................................................................................................................14
2.2.4. PerStore 的例子..............................................................................................14
2.3. Session Façade 模式...............................................................................................16
2.3.1. 意图.................................................................................................................16
2.3.2. 动机.................................................................................................................16
2.3.3. 结构.................................................................................................................17
2.3.4. PetStore 中的例子..........................................................................................18
2.1.4.8 概述.................................................................................................18
2.1.4.9 ShoppingClientFacadeLocalEJB.............................................................18
2.3.5. GOF 中Facde 模式........................................................................................19
2.4. Fast-Lane Reader 模式...........................................................................................20
2.4.1. 意图.................................................................................................................20
2.4.2. 动机.................................................................................................................20
2.4.3. 结构.................................................................................................................21
2.4.4. PetStore 中的例子..........................................................................................21
PetStore 中EJB 的设计模式
2/2
2.1.4.10 CatalogDAO....................................................................................21
2.1.4.11 CatalogWebImpl..............................................................................21
2.1.4.12 ProductListTag ................................................................................22
2.5. Page-by-Page Iterator 模式.....................................................................................23
2.5.1. 意图.................................................................................................................23
2.5.2. 动机.................................................................................................................24
2.5.3. 结构.................................................................................................................25
2.5.4. PetStore 的例子..............................................................................................25
2.1.4.13 CatalogDAOImp .............................................................................25
2.1.4.14 ProductItemListTag.........................................................................26
2.5.5. GOF 的Iterator 模式......................................................................................27
2.6. ServiceLocator 模式...............................................................................................27
2.6.1. 意图.................................................................................................................28
2.6.2. 动机.................................................................................................................28
2.6.3. 结构.................................................................................................................28
2.6.4. PetStore 中的例子..........................................................................................29
2.1.4.15 ServiceLocatorImpl.........................................................................29
2.1.4.16 我们项目的例子.............................................................................30
2.6.5. GOF 模式........................................................................................................32
2.1.4.17 Singleton 模式................................................................................32
2.7. Local 模式...............................................................................................................33
2.7.1. 意图.................................................................................................................33
2.7.2. 动机.................................................................................................................33
2.7.3. 结构.................................................................................................................33
2.7.4. PetStore 例子..................................................................................................35
2.8. CMR 模式...............................................................................................................35
2.8.1. 意图.................................................................................................................35
2.8.2. 动机.................................................................................................................35
2.8.3. 结构.................................................................................................................35
2.8.4. PetStore 中的例子..........................................................................................36
2.9. 业务代表模式.........................................................................................................37
2.9.1. 意图.................................................................................................................38
2.9.2. 动机.................................................................................................................38
2.9.3. 结构.................................................................................................................39
2.9.4. PetStore 中的例子..........................................................................................39
2.9.5. GOF 模式........................................................................................................41
2.1.4.18 Proxy 模式......................................................................................41
3. EJB 模式关系.........................................................................................................................42
4. 相关的资料.............................................................................................................................43
5. 总结........................................................................................................................................43
PetStore 中EJB 的设计模式
3/3
PetStore 中EJB 的设计模式
Liubing (bliu76@yeah.net)
1. 概述
通过分析数据模型,和实际操作PetStore 我们大概对它的数据模型有所了解。现在开始
分析系统EJB 层的设计模式。首先什么是模式?看Gof 的《设计模式》的定义,就是对被
用来在特定场景下解决一般设计问题的类和相互通信的对象描述。唉!太深沉了。一头雾水。
其实,就是一些经验,并且经过科学整理,可以在某种场合下反复使用,解决一些问题。当
然在《设计模式》一书罗列出23 中模式,并且进行了详细描述。今天我们所说的模式,是
PetStore 中的EJB 设计经验。
关于设计模式,我有很多感触,Gof 的书我不知看了多少遍,可总是不太明白,我几年
没有使用C++了,里面的例子,看着很不爽。板桥先生网上的例子很简单明了,但是经过一
段时间的学习,有点不尽兴的感觉。于是又看了其他的几本书,心中有了一些感觉,可是实
际写代码很难用上,并且现在项目使用J2EE,于是我决定分析PetStore 源码,看看这些牛
人是怎样使用模式的。在我们的项目开发中也照葫芦画瓢,使用一把。
关于PetStore 的模式,SUN 的站点列出了以下几种模式,当然其中的FrontController 属
于Web 层的。
Pattern Intent
Data Access
Object
Decouple business logic from data access logic and adapt the resource being
accessed, so that the type of resource can change easily and independently.
Fast-Lane
Reader
Accelerate read-only data access by not using enterprise beans.
Front Controller
Centralize view management (navigation, templating, security, etc.) for a Web
application in a single object that handles incoming client requests.
Page-by-Page
Iterator
Efficiently access a large, remote list by retrieving its elements one sublist of
value objects at a time.
Session Facade Provide a unified, workflow-oriented interface to a set of enterprise beans.
Value Object
Efficiently transfer remote, fine-grained data by sending a coarse-grained
view of the data.
在《J2EE 核心模式》一书中列出了以下几种模式,当然包括了以上的几种模式。这本书不
错,可惜翻译的很次。
业务代表
值对象
值对象组装器
PetStore 中EJB 的设计模式
4/4
值对象列表
会话外观
服务器定位
数据访问对象
服务激发器
我们首先知道EJB 层有这些模式,我把这些模式简单介绍一下,包括它的意图,动机,
结构,然后看在PetStore 中使用了那些,又是怎样使用的。我想把我所理解的写出,如果不
对的地方,请大家指出。
2. 模式分类
2.1. Data Access Object 模式
这个模式SUN 上有详细的描述,并且《程序员 6 期》中有板桥先生的一遍文章介绍了它。
这模式使用了GoF 中Bridge 和Adapter 模式。如果大家不熟悉,最好看下Gof 的介绍,现
在我感觉GoF 的书当作一个模式参考手册比较不错。一般刚开始就看这本,很难看懂,这
样就打消了大家的积极性,这年头,有学习上进的想法就很不错了。在被人打击,太不好了。
2.1.1. 意图
Decouple business logic from data access logic and adapt the resource being accessed, so that
the type of resource can change easily and independently.(算了我不翻译了,实际就是分离业
务逻辑和数据读取,把数据的读取写到了DAO 中。这样增强了系统的灵活性。如果你看过
GoF 的书,这个口号你一定记忆有心(针对接口编程,而不是针对实现编程),当然了老米
的态度决定一切也很有哲理。设计模式就是把调用与实现分离,如果你感觉,很罗嗦被分的
乱七八糟,实现一个东西要好多类和接口,这样你就对设计模式有了一定的了解了。)
2.1.2. 动机
These problems can be avoided by removing data access logic from
enterprise beans and abstracting data access functionality into a
separate interface. Enterprise beans carry out their business logic
in terms of operations on that interface, which is implemented by a
data access object (DAO) appropriate for the type of resource being
used. (就是业务逻辑中不负责数据的存取,把它放到DAO 中,这些数据的
格式,提供商一旦发生改变,只需修改DAO 即可)
For example, the Java Pet Store application's OrderEJB component
accesses a database through its associated OrderDAO class, which knows
how to perform load, save, and find operations on order data in the
PetStore 中EJB 的设计模式
5/5
persistent store. Because the bean delegates its persistence-related
tasks to the DAO, it can concentrate on implementing business methods.
At deployment time, the application administrator configures the
implementation of OrderDAO to be one of OrderDAOCS, OrderDAOOracle, or
OrderDAOSybase, depending on whether an Cloudscape, Oracle, or Sybase
database is used. No matter what choice is made, the OrderEJB is
unaffected, because it is programmed to an interface, not to an
implementation.(很简单,我就不翻译了吧,要不就被我糟蹋原意了)。
不过我现在使用的是JB6.0+Weblogic6。1 开发bmp,我们大多使用了JB 的
向导,它自动生成了代码,可是它没有实现这种模式.在SessionBean 中我们
封装了JDBC 的数据读取,有点向这种模式。
2.1.3. 结构
它使用了GOF 中的Bridge 和Adapter 模式。整个结构图如下:
大家可能看明白,其实就是在BusinessObject 中提供了业务逻辑方法,假如它必须要读取
数据,但是这个数据可能存在Oracle 数据库中,又有可能存在excel 文件中,也许存在XML
文件中,如果我们在这个方法中直接读取数据,那就要写这样的语句
switch (DATA_TYPE){
case ORACLE:
通过JDBC 读取Oracle 数据
break;
case Excel:
通过专门的API 进行读取,Excel 文件
PetStore 中EJB 的设计模式
6/6
break;
case XML
通过JDOM 进行,分析XML 文件;
break;
}
这样,业务逻辑中到处是数据的读取,并且修改程序,很麻烦。于是这些牛人,想出一
个使用接口DAO(就是DataAccessObject),它什么具体的事都不做,就申明几个方法,在
业务逻辑类中,只管调用它就行了,好像在说我能做什么,不要管我怎样做,就想我们的销
售接项目一样,说我们公司什么事都可以做。但是项目接下以后,就由我们这些命苦的开发
人员来实现。最后也就是DAOImplementor 根据数据的不同有不同的具体类来读取(它有可
能是DAOImplementor_ORACLE 类实现读取Oracle 数据库,DAOImplementor_EXCEL,
实现通过API 读取Excel 文件,DAOImplementor_XML 实现读取XML 文件)。这样你可,
在业务逻辑类中,不负责数据的读取,只关注业务逻辑的实现,它只需调用DAO 获得数据,
真正实现数据的读取是DAOImplementor_ORACLE 这样的类。
我解释的不知你是否明白,反正我是知道了。多看几次就明白了,其实很简单。
2.1.4. PetStore 的例子
2.1.4.1 概述
首先我们看UML 图,这是PetStore 自带UML 图,我用Rose 画还需要时间,他们使用
了一种叫ARGOUML 的工具,你可以下载,是免费的感觉远不如Rose.
PetStore 中EJB 的设计模式
7/7
这其中使用了GoF 的工场模式,也是简单工场模式,它负责使用那个具体实现类,好像
大家都可以干这活,它来选择到底由谁来做,就是我们的人力资源的。
我们在仔细分析一下,就是在CatalogEJB 类中有一些业务逻辑,如getProduct,它来取
某项分类的产品,这样也许读取数据库,也有可能读取XML文件,于是它就调用CatalogDAO
的方法,来实现,但是CatalogEJB 并不知道数据到底存在那里,它只管读就行了。可是
CatalogDAO 也只是声明这个方法,真正辛苦干事情的就是CatalogDAOImpl,它负责读取数
据库。我们不要忘记,在CatalogEJB 有个方法,它调用了工场,它来确定又谁来做。
唉,下面是我使用Rose 的逆向工程,获得的UML 图。
PetStore 中EJB 的设计模式
8/8
CatalogDAOFactory
getDAO()
(from dao)
CatalogDAOImpl
getDataSource()
getCategory()
getCategories()
getProduct()
getProducts()
getItem()
getItems()
searchItems()
(f rom dao )
CatalogEJB
ejbCreate()
setSessionContext()
ejbRemove()
ejbActivate()
ejbPassivate()
destroy()
getCategory()
getCategories()
getProducts()
getProduct()
getItems()
getItem()
searchItems()
<<EJBSession>>
CatalogDAO
getCategory()
getCategories()
getProduct()
getProducts()
getItem()
getItems()
searchItems()
(from dao)
CatalogLocalHome
create()
(f ro m ej b)
2.1.4.2 CatalogEJB
public class CatalogEJB implements SessionBean {
//那个光说话,不做是的家伙,真正做事CatalogDAOImpl 类,CatalogEJB 不知道,
其实现实生活中就有这种事情
protected CatalogDAO dao;
public void ejbCreate() {
try {
//使用工程模式,产生DAO
dao = CatalogDAOFactory.getDAO();
} catch (CatalogDAOSysException se) {
}
}
PetStore 中EJB 的设计模式
9/9
//获得产品信息
public Page getProducts(String categoryID, int start, int count, Locale l) {
try {
//调用DAO,实现业务逻辑
return dao.getProducts(categoryID, start, count, l);
}
catch (CatalogDAOSysException se) {
throw new EJBException(se.getMessage());
}
}
2.1.4.3 CatalogDAO
public interface CatalogDAO {
//声明能力
public Page getProducts(String categoryID, int start, int count, Locale l)
throws CatalogDAOSysException;
}
2.1.4.4 CatalogDAOImpl
DAOpublic class CatalogDAOImpl implements CatalogDAO {
public Page getProducts(String categoryID, int start, int count, Locale l){
try {
c = getDataSource().getConnection();
ps = c.prepareStatement("select a.productid, name, descn "
+ "from (product a join "
+ "product_details b on "
+ "a.productid=b.productid) "
+ "where locale = ? "
+ "and a.catid = ? "
+ "order by name",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ps.setString(1, l.toString());
ps.setString(2, categoryID);
rs = ps.executeQuery();
//读取数据库
rs.close();
ps.close();
}
catch (SQLException se) {
PetStore 中EJB 的设计模式
10/10
}
}
2.1.4.5 CatalogDAOFactory
public class CatalogDAOFactory {
public static CatalogDAO getDAO() throws CatalogDAOSysException {
CatalogDAO catDao = null;
try {
//依据系统配置的信息,产生一个实现类
catDao = (CatalogDAO) Class.forName(className).newInstance();
} catch (NamingException ne) {
} catch (Exception se) {
}
return catDao;
}
}
2.1.5. GOF 模式关系
我可以简单解释以下。
2.1.4.6 Bridge 模式
结构
意图:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
适用性
PetStore 中EJB 的设计模式
11/11
• 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是
因为,在程序运行时刻实现部分应可以被选择或者切换。
• 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时B r i d g e 模
式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
• 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
2.1.4.7 Adapter 模式
它有两种方式实现。比较简单,我就不多说了。
2.2. Value Object 模式
值对象模式,在SUN 的站点上有详细的描述,并且《J2EE 核心模式》上也有详细描述,
其实这种模式,我们每天都在使用,目的就是减少网络流量,提高效率,许多书上叫做的粗
粒度。和这种模式相关的还有复合实体,值对象组装器,值列表处理器。
我感觉在项目开发中有一个人负责系统的全部entityBean,为每个entityBean 建立值对
象,并且建立他们之间的关系。其他的开发人员只管调用就行了,如果数据库修改,它来修
改。这种方式,我建议大家使用。
2.2.1. 意图
Efficiently transfer remote, fine-grained data by sending a
coarse-grained view of the data.
我们知道EJB 的调用使用了远程方法,它的效率一般要远低于本地方法的
调用,这样我们要读取一个对象,如果使用他的getXX 方法就多次调用了远
程,效率很低,如果一次性读到值对象,这就减少了远程调用。
我们在实际开发中,一般为每个EntityBean 建一个值对象,并且在
entityBean 中的Home 接口中,增加一个create 方法,参数就是值对象. 并
且在接口中增加setData 和getData 方法。
?? Home 接口
public interface TAccountAcptRemoteHome extends javax.ejb.EJBHome
{
//在创建时,使用值对象,如果修改数据结构,接口不需改变,只修改
属性就行了
public TAccountAcptRemote create(TAccountAcptModel data)
throws CreateException, RemoteException;
PetStore 中EJB 的设计模式
12/12
}
?? 声明接口(远程或本地接口)
public interface TAccountAcptRemote extends javax.ejb.EJBObject {
//通过这个接口,一次性获得值对象,不需分别使用getXX,减少网络
调用次数,提高效率
public TAccountAcptModel getData() throws RemoteException;
public void getData(TaccountAcptModel data) throws
RemoteException;
}
?? 值对象
public class TAccountAcptModel implements java.io.Serializable {
public java.lang.String acceptId ;
public java.lang.String accountId ;
public java.lang.String ownerId ;
public java.lang.String accountName;
public java.lang.String accountAddr;
public java.lang.String accountZip ;
public java.lang.String bankId ;
public java.lang.String account ;
public java.lang.String payTypeId ;
public java.lang.String state ;
public java.lang.String postMode ;
public java.lang.String postAddr ;
public java.lang.String postZip ;
PetStore 中EJB 的设计模式
13/13
public java.lang.String postMan ;
public java.math.BigDecimal preSum ;
public java.sql.Date createDate ;
public java.sql.Date unsignDate ;
}
2.2.2. 动机
Some entities have a set of attributes that are always used together.
In the Java Pet Store application, the contact information of a
customer (city, state, zip code, etc.) is an example of one such group.
Suppose that in total, a customer's contact information is composed
of 15 individual attributes, each accessible by a corresponding getXXX
method in CustomerEJB. Then, every time a customer's contact information
is requested, 15 remote getXXX calls will be invoked on the CustomerEJB,
one for each attribute. This will incur heavy costs in network traffic
and EJB container resource usage.
The Java Pet Store application reduces these costs by adopting a
coarse-grained view of the fine-grained contact information. It
aggregates the contact information-related attributes of the
CustomerEJB into an instance of ContactInformation. This instance, or value
object, is then serialized and sent over the network to a requesting
client, where the object is deserialized. Subsequent read accesses go
through the value object rather than the remote entity object. Since
these accesses are local, they require no server communication and use
fewer resources.
PetStore 中EJB 的设计模式
14/14
2.2.3. 结构
EnterpriseBean 业务对象,实现了业务逻辑
ValueObject 实现了串行化值对象。
2.2.4. PerStore 的例子
PetStore 中存在大量的例子,基本上每个EJB 中都可以找到它的踪影。
PetStore 中EJB 的设计模式
15/15
?? 如值对象ProfileInfo(一定要实现Serializable 接口,就是串行化)
public class ProfileInfo implements java.io.Serializable {
private String defaultPreferredLanguage = null;
private String defaultFavoriteCategory = null;
private boolean defaultMyListPreference = false;
private boolean defaultBannerPreference = false;
public ProfileInfo( String defaultPreferredLanguage,
String defaultFavoriteCategory,
boolean defaultMyListPreference,
boolean defaultBannerPreference) {
this.defaultPreferredLanguage = defaultPreferredLanguage;
this.defaultFavoriteCategory = defaultFavoriteCategory;
this.defaultMyListPreference = defaultMyListPreference;
this.defaultBannerPreference = defaultBannerPreference;
}
public String getPreferredLanguage() {
return defaultPreferredLanguage;
}
public String getFavoriteCategory() {
return defaultFavoriteCategory;
}
public boolean getBannerPreference() {
return defaultBannerPreference;
}
public boolean getMyListPreference() {
return defaultMyListPreference;
}
}
?? 使用类,提高调用粗粒度,使用值对象
public abstract class CustomerEJB implements javax.ejb.EntityBean {
//一次调用,获得值对象,提高效率
public abstract ProfileLocal getProfile();
//设置值对象
public abstract void setProfile(ProfileLocal profile);
}
PetStore 中EJB 的设计模式
16/16
2.3. Session Façade 模式
众所周知在Gof 中有Façade(外观)模式,我们只是把这种模式应用到EJB 中罢了。它
的目的其实很明显,就是给子系统提供一个一致的接口,这样使系统业务逻辑集中,
使系统的业务逻辑和调用部分松耦合。现在我是一般这些使用的,首先定义一些
EntityBean,和一些实现业务逻辑的SessionBean,然后在把这些业务逻辑封装成
SessionBean 供web 层调用,一般在调用层不负责事务的管理,一个业务逻辑就是一个
独立的事务。在Web 层其实只需获得画面的数据,和简单的校验,然后直接提交到
EJB 层,进行处理,这样使Web 的功能很简单。
2.3.1. 意图
Provide a unified, workflow-oriented interface to a set of enterprise
beans.
把SessionBean 用作Façade 以封装参与业务的多个对象,提供给用户统一的粗粒度访问。
简单一些,就是尽可能把事情放在EJB 层来做,接口越简单越好,最好调用层不负责事务,
一次调用就是一次事务,累死EJB。
2.3.2. 动机
这些是抄J2ee 核心模式的内容,显得深沉一些。
?? 通过隐藏了业务组件之间所有的复杂交互活动,向客户提供一个简单的接口
?? 减少通过网络并跨越服务层被直接暴露给客户端的业务对象数目
?? 向客户隐藏业务组件之间的交互和相互
在下图大家应该能够看明白一些,Client 如果处理一件事情,需要调用SessionBean1,
和两个实体Bean,这样客户端要负责事务,并且多次网络调用,降低的效率。系统一定修改,
两侧都要大修。你应该认为不爽吧。
如果我们把这些业务逻辑封装在SessionFacade 里面,这样调用很简单,实际远程调用
只需一次,接口也很简单。
PetStore 中EJB 的设计模式
17/17
2.3.3. 结构
我看下结构,其实就是在SessionFacade 中,封装业务逻辑,简化接口,大家应该一看就明
白。
PetStore 中EJB 的设计模式
18/18
2.3.4. PetStore 中的例子
2.1.4.8 概述
在PetStore 中就使用了这种模式,不过大家一般在开发中都可能使用这种模式,只是自己不
知道罢了。
2.1.4.9 ShoppingClientFacadeLocalEJB
public class ShoppingClientFacadeLocalEJB implements SessionBean {
/*
* Asume that the customer userId has been set
*/
//它封装了调用客户的EntityBean
public CustomerLocal getCustomer() throws FinderException {
if (userId == null) {
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: userId is not set" );
}
try {
InitialContext ic = new InitialContext();
Object o = ic.lookup("java:comp/env/ejb/local/Customer");
CustomerLocalHome home =(CustomerLocalHome)o;
customer = home.findByPrimaryKey(userId);
} catch (javax.naming.NamingException nx) {
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: caught " + nx);
}
return customer;
}
//它封装了产生客户方法
public CustomerLocal createCustomer(String userId) {
try {
InitialContext ic = new InitialContext();
Object o = ic.lookup("java:comp/env/ejb/local/Customer");
CustomerLocalHome home =(CustomerLocalHome)o;
customer = home.create(userId);
this.userId = userId;
} catch (javax.ejb.CreateException ce) {
throw new GeneralFailureException("ShoppingClientFacade: failed to create
PetStore 中EJB 的设计模式
19/19
customer: caught " + ce);
} catch (javax.naming.NamingException nx) {
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: caught " + nx);
}
return customer;
}
}
2.3.5. GOF 中Facde 模式
意图
为子系统中的一组接口提供一个一致的界面,F a c a d e 模式定义了一个高层接口,这个
接口使得这一子系统更加容易使用。
结构
动机
• 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越
来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,
也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用
上的困难。F a c a d e 可以提供一个简单的缺省视图,这一视图对大多数用户来说已
经足够,而那些需要更多的可定制性的用户可以越过f a c a d e 层。
• 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入f a c a d e 将这个子系
统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
• 当你需要构建一个层次结构的子系统时,使用f a c a d e 模式定义子系统中每层的入
口点。如果子系统之间是相互依赖的,你可以让它们仅通过f a c a d e 进行通讯,从
而简化了它们之间的依赖关系。
PetStore 中EJB 的设计模式
20/20
2.4. Fast-Lane Reader 模式
我们都知道使用EJB 的效率低,但是在某些情况下效率很重要,这样这些牛人就不使用
EJB 而是直接使用DAO 来读取数据库,这样避免使用EJB 的事务,串行化等。不过使用
EJB 的效率,是个问题,目前我们的营业系统因客户数量的巨大,效率很低,我最头痛的就
是这件事情,不知大家有没有好的建议,我准备把我们系统中的查询,报表统计改成不使用
EJB,也是这种模式。
2.4.1. 意图
Accelerate read-only data access by not using enterprise beans。提高只读数据的读取,而不使用
EJB.
2.4.2. 动机
Sometimes it's more important to access a list of data efficiently,
than that the data in the list be up-to-date. For example, when a user
browses the Java Pet Store catalog, it's not crucial that what they
see on the screen be entirely consistent with what's in the database.
In the interests of usability, however, it is important that the
catalog data be displayed quickly–and thus retrieved quickly.
The Fast-Lane Reader pattern can accelerate the retrieval of large
lists of items from a resource. Instead of going through an enterprise
bean, an application accesses data more directly by going through a
data access object. This way, the application avoids the overhead
associated with using enterprise beans (remote method invocation,
transaction management, data serialization, etc.).
In the Java Pet Store application, when a user browses the catalog,
items are loaded from the database through the CatalogDAO instead of
the CatalogEJB component. The CatalogDAO is an example of a fast-lane
reader, because it facilitates quicker read access.
有些时候,高效地存取数据比获得最新的数据更重要。在Java Pet Store 中,当一个用户浏览商
店的目录时,屏幕与数据库内容吻合不是至关紧要的,相反,迅速显示和重新获得非常重要。
FLR 模式可以加速从资源中重新获得大型的列数据项的速度,它不用EJB,而是更直接地通过
DAO 来存取数据,从而消除EJB 的经常开支(例如远程方法调用、事务管理和数据序列化等)。
在Java Pet Store 这个例子中,当一个用户浏览目录时,通过CatalogDAO(而不是CatalogEJB)
PetStore 中EJB 的设计模式
21/21
从数据库加载数据项,而CatalogDAO 是一个Fast Lane Reader 的实例,使得读访问变得迅速
与DAO 模式不同的是,FLR 是一个优化的模式,但不是要替代原有的访问机制,而是作为补充
使其完备。当你频繁地只读大型的列数据和不必存取最新的数据时,使用FLR 将是非常合适的。
2.4.3. 结构
客户端直接调用FastLaneReader,而不是使用EJB 来获得数据,当然EJB 接口仍然保留。
2.4.4. PetStore 中的例子
2.1.4.10 CatalogDAO
定义数据的存取。使用了DAO 模式,
public interface CatalogDAO {
public Category getCategory(String categoryId, Locale locale) throws
CatalogDAOSysException;
public Product getProduct(String productId, Locale locale) throws
CatalogDAOSysException;
public Item getItem(String itemId, Locale locale) throws
CatalogDAOSysException;
}
2.1.4.11 CatalogWebImpl
客户端直接,调用DAO,而不使用EJB,读取产品信息
public class CatalogWebImpl implements java.io.Serializable {
protected CatalogDAO dao;
PetStore 中EJB 的设计模式
22/22
public CatalogWebImpl() {
try {
//获得DAO 对象
dao = CatalogDAOFactory.getDAO();
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
public Category getCategory(String categoryId, Locale locale) {
try {
//使用DAO,获得数据,而不使用EJB
return dao.getCategory(categoryId, locale);
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
public Product getProduct(String productId, Locale locale) {
try {
//使用DAO,获得数据,而不使用EJB
return dao.getProduct(productId, locale);
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
public Item getItem(String itemId, Locale locale) {
try {
//使用DAO,获得数据,而不使用EJB
return dao.getItem(itemId, locale);
} catch (CatalogDAOSysException se) {
throw new GeneralFailureException(se.getMessage());
}
}
}
2.1.4.12 ProductListTag
定义一些TagLib 实现产品的列表,当然使用了CatalogWebImp,实际就是DAO,显示出产品
信息。
public class ProductListTag extends ListTag {
private String category = null;
PetStore 中EJB 的设计模式
23/23
private boolean hasNext = false;
protected void initParamPrefix() {
paramPrefix = "productList_" + category + "_";
}
protected Collection findCollection() throws Exception {
CatalogWebImpl catalog =
(CatalogWebImpl)
pageContext.getServletContext().getAttribute(WebKeys.CatalogModelKey);
if (catalog == null) {
return null;
}
Locale locale = JSPUtil.getLocale(pageContext.getSession());
ListChunk prodList = null;
Collection products = null;
// 获得产品列表
prodList = catalog.getProducts(this.category, startIndex-1, numItems, locale);
products = prodList.getCollection();
if ((startIndex -1 + products.size()) < prodList.getTotalCount()) hasNext = true;
else hasNext = false;
return(products);
}
}
2.5. Page-by-Page Iterator 模式
在我们系统中一般有查询,或者显示信息列表。如在BBS 必须显示贴之信息,但是我
们并不是一次把版面的所有贴之全部取出。因为我们一般不会把整个版都看,这样每次要读
到信息巨大,浪费了巨大的内存。
2.5.1. 意图
Efficiently access a large, remote list by retrieving its elements one
sublist of value objects at a time.
为了提高远程,大数据,而一次读取值对象的部分对象。实际上就是不一次全部读取,而是
每次读取其中的一部分。不过在实际开发中,如果数据量不大,并且都要显示应该一次性读
取,不要使用这种模式,具体数据量多大才使用,需要结合实际情况。
PetStore 中EJB 的设计模式
24/24
2.5.2. 动机
Distributed database applications often require users to consider a
long list of items, such as a catalog or a set of search results. In
these situations, presenting the entire list at once is often
unnecessary (the user isn't interested in all the items) or impossible
(there isn't enough space for all the items).
Furthermore, when retrieving a list of items, it would be very
expensive to use entity beans. One cost comes from using remote finder
methods to collect the requested beans; an additional, larger cost
comes from making remote calls to each bean to get data for the user.
These problems can be avoided by using a page-by-page iterator. Through
such an iterator, a client object can traverse a large list, one sublist
or page of value objects at a time; each page can be as big or as small
as the client desires. Consequently, the application uses fewer
resources to satisfy the client's immediate needs.
In the Java Pet Store application, the JSP page product.jsp displays only
a portion of an item list at any time, retrieving items from the
page-by-page iterator ProductItemListTag. When the client wants to see
the next or previous items in the list, product.jsp again calls on the
iterator to retrieve these items.
分布式数据库的应用经常需要用户考虑一长列数据项,例如一个目录或一个搜索结果的集
合。在这些情况下,立刻提供全列的数据经常不必要(用户并不是对所有的数据项感兴趣)
或不可能(没有足够的空间)。此外,当重新获得一列数据项时,使用Entity Bean 的代价
将非常高昂,一个开销来自于使用远程探测器来收集Requested Bean,另外,更大的开销
来自对每个Bean 产生远程调用以从用户获得数据。
通过Iterator,客户机对象能一下子重新获得一个子列或者页的values Object,每一页都
刚好满足客户机的需求,因此,程序使用较少的资源满足了客户机的立刻需求。
在Java Pet Store 这个例子中,JSP 页面product.jsp 任何时候只显示一个数据列的一部
分,从ProductItemListTag(Page-by-Page Iterator)重新获得数据项,当客户机希望看
到列中的别的数据项,product.jsp 再次调用Iterator 重新获得这些数据项,
PetStore 中EJB 的设计模式
25/25
2.5.3. 结构
实际上在Java 中使用Collection,就实现了GoF 中Iteraror 模式,一般从数据库中读取数据
放入到Vector, , ArrayList 等中,然后就可义进行显示。并且一般这种模式结合,
ValueObject,Fast_Lane Reader 模式。
2.5.4. PetStore 的例子
2.1.4.13 CatalogDAOImp
public class CatalogDAOImpl implements CatalogDAO {
//一次读取部分数据,开始值startIndex,总条数count
public ListChunk getProducts(String categoryId, int startIndex,
int count, Locale locale) throws CatalogDAOSysException {
int localCount = 0 ;
String qstr =
"select productid, name, descn " +
"from " +
DatabaseNames.getTableName(DatabaseNames.PRODUCT_TABLE, locale) +
" where category = " + "'" + categoryId + "' " + " order by name";
Debug.println("Query String is:" + qstr);
int num =
getCount(DatabaseNames.getTableName(DatabaseNames.PRODUCT_TABLE,
locale) + " where category = " + "'" + categoryId + "' ");
ArrayList al = new ArrayList();
Statement stmt = null;
ResultSet rs = null;
try {
getDBConnection();
stmt = dbConnection.createStatement();
PetStore 中EJB 的设计模式
26/26
rs = stmt.executeQuery(qstr);
HashMap table = new HashMap();
// skip initial rows as specified by the startIndex parameter.
while (startIndex-- > 0 && rs.next());
// Now get data as requested.
while (count-- > 0 && rs.next()) {
int i = 1;
String productid = rs.getString(i++).trim();
String name = rs.getString(i++).trim();
String descn = rs.getString(i++).trim();
Product product = null;
if (table.get(productid) == null) {
product = new Product(productid, name, descn);
table.put(productid, product);
al.add(product);
localCount++;
}
}
} catch(SQLException se) {
throw new CatalogDAOSysException("SQLException while getting " +
"multiple products for cat " + categoryId + " : " +
se.getMessage());
} finally {
closeResultSet(rs);
closeStatement(stmt);
closeConnection();
}
ListChunk rl = new ListChunk(num, al, startIndex, localCount);
return rl;
}
2.1.4.14 ProductItemListTag
public class ProductItemListTag extends ListTag {
protected Collection findCollection() {
CatalogWebImpl catalog =
(CatalogWebImpl)
pageContext.getServletContext().getAttribute(WebKeys.CatalogModelKey);
if (catalog == null) {
return null;
}
PetStore 中EJB 的设计模式
27/27
Locale locale = JSPUtil.getLocale(pageContext.getSession());
ListChunk itemList = null;
Collection items = null;
//进行读取部分数据
itemList = catalog.getItems(productId, startIndex-1, numItems, locale);
items = itemList.getCollection();
if ((startIndex -1 + items.size()) < itemList.getTotalCount()) hasNext = true;
else hasNext = false;
return(items);
}
}
2.5.5. GOF 的Iterator 模式
意图
提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
结构
动机
• 访问一个聚合对象的内容而无需暴露它的内部表示。
• 支持对聚合对象的多种遍历。
• 为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。
2.6. ServiceLocator 模式
这种模式在《J2EE 核心模式》有详细描述,虽然在SUN 上没有介绍,但在petstore1.3 版
本中使用了它。
PetStore 中EJB 的设计模式
28/28
2.6.1. 意图
我们使用这种模式来抽取所有的JNDI 使用,并且隐藏了Context 的初始化,Ejb 对象的
LookUp,以及narrow。系统的所有客户端使用统一代码,来降低代码的的复杂性,提供一
致控制,并且使用缓存提高性能。
2.6.2. 动机
?? 抽取复杂性
通过封装了查找,创建过程的复杂性,对系统的所有cilent,统一处理。
?? 向客户端提供统一的服务访问
?? 有利用添加新的业务组件
?? 提高网络性能
?? 通过缓存提高性能
2.6.3. 结构
PetStore 中EJB 的设计模式
29/29
2.6.4. PetStore 中的例子
2.1.4.15 ServiceLocatorImpl
public class ServiceLocatorImpl implements ServiceLocator, java.io.Serializable {
protected HttpSession session;
protected WebClientController wcc;
public ServiceLocatorImpl() { }
//定位ejb
public WebClientController getWebClientController() {
WebClientController wcc =
(WebClientController)session.getAttribute(WebKeys.WEB_CLIENT_CONTROLLER);
if ( wcc == null ) {
try {
InitialContext ic = new InitialContext();
String wccClassName = (String)
ic.lookup(JNDINames.WEB_CLIENT_CONTROLLER_IMPL);
wcc = (WebClientController)
Beans.instantiate(this.getClass().getClassLoader(), wccClassName);
wcc.init(session);
} catch (Exception exc) {
exc.printStackTrace();
throw new RuntimeException ("Cannot create bean of class
WebClientController");
}
session.setAttribute(WebKeys.WEB_CLIENT_CONTROLLER, wcc);
}
return wcc;
}
/**
*
* Create the WebClientController which in turn should create the
* EJBClientController.
*
*/
public void sessionCreated(HttpSessionEvent se) {
this.session = se.getSession();
wcc = getWebClientController();
this.session.setAttribute(WebKeys.SERVICE_LOCATOR, this);
PetStore 中EJB 的设计模式
30/30
}
/**
*
* Destroy the WebClientController which in turn should destroy the
* EJBClientController.
*
*/
public void sessionDestroyed(HttpSessionEvent se) {
if (wcc != null) wcc.destroy();
wcc = null;
}
}
2.1.4.16 我们项目的例子
当初我们项目使用JB 开发,EJB 服务器有的使用了BAS4.5 和WebLogic6。1,这样EJB
定位,方法不一致,我们使用这种模式,这使用了GoF 中的Singleton 模式,这样缓存context
提高了效率。不需要每次都要getInitialContext。这个代码对大家应该有用。
public class ServiceLocator {
private static ServiceLocator me;
Context context = null;
//系统服务器信息,如果改动只需,设置CURRENTSERVER
private static String WEBLOGICSERVER="weblogic6.1";
private static String BASSERVER="bas4.5";
private static String CURRENTSERVER="weblogic6.1";
//联接EJB 服务器参数
private final static String EJBSERVERURL="t3://localhost:7001";
// AIX 服务器
//private final static String EJBSERVERURL="t3://192.168.4.25:7001";
//private final static String EJBUSERNAME="system";
//private final static String EJBPASSWORD="password";
//weblogic 的guest 用户如果不删除,可以使用null
private final static String EJBUSERNAME=null;
private final static String EJBPASSWORD=null;
PetStore 中EJB 的设计模式
31/31
/**
*初始化Context
* @return
* @throws Exception
*/
private Context getInitialContext() throws Exception {
String url = EJBSERVERURL;
String user =EJBUSERNAME;
String password =EJBPASSWORD;
Properties properties = null;
try {
//当前服务器为Weblogic6.1 时
if(CURRENTSERVER.equals(WEBLOGICSERVER)){
properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, url);
if (user != null) {
properties.put(Context.SECURITY_PRINCIPAL, user);
properties.put(Context.SECURITY_CREDENTIALS, password == null ?
"" : password);
}
return new InitialContext(properties);
//当前服务器为BAS 时
}else{
return new InitialContext();
}
}
catch(Exception e) {
e.printStackTrace();
System.out.println("Please make sure that the server is running.");
throw e;
}
}
private ServiceLocator() {
try {
context = getInitialContext();
} catch(Exception e) {
e.printStackTrace();
}
}
PetStore 中EJB 的设计模式
32/32
/**
*初始化ServiceLocator
* @return
*/
public static ServiceLocator getInstance() {
if (me == null) {
me = new ServiceLocator();
}
return me;
}
/**
*根据JNDI 名字,取得EJB Home
* @param name JDNI 名字
* @param clazz Home class 名字
* @return
*/
public EJBHome getHome(String name, Class clazz) {
try {
Object objref = context.lookup(name);
EJBHome home = (EJBHome)PortableRemoteObject.narrow(objref, clazz);
return home;
} catch(Exception e){
e.printStackTrace();
return null;
}
}
}
2.6.5. GOF 模式
2.1.4.17 Singleton 模式
实际在我们使用了这种模式,ServiceLocator 实例就使用这种模式,它只有一个实例,从而
保证只初始Context 一次,提高了效率
?? 意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
?? 适用性
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个
扩展的实例时。
PetStore 中EJB 的设计模式
33/33
?? 结构
2.7. Local 模式
2.7.1. 意图
由于EJB 的效率低,如果部分EJB 仅是在内部使用(同一个java VM,),而不是远程调用,
就应该使用本地方法。如果你看过PetStore 的EJB 层,就会发现大部分都使用Local 方法。
只有在提供Facde 的SessionBean 才使用远程接口。这是在EJB2.0 才支持的,实际在我们
的项目中开始是第一次使用EJB2.0,并没有使用本地方法,后来使用本地方法,具体效率
提高多少,我也不知道。其实在资料中一般不把它作为模式来讲,但是我认为这是一种模式。
大家在自己的项目中最好使用它。据说在weblogic 7.0 的web 层与ejb 容器共享一个JVM,
所以可以使用本地方法,在两层之间调用。
2.7.2. 动机
Local interfaces allow enterprise javabeans to work together within the same EJB container
using different semantics and execution contexts. The EJBs are usually co-located within the same
EJB container and ex ecute within the same Java Virtual Machine (JVM). This way, they do not
use the network to communicate and avoid the over-head of a Java Remote Method
Invocation-Internet Inter-ORB Protocol (RMI-IIOP) connection.
2.7.3. 结构
结构一般是,在远程SessionBean 中调用本地接口EntityBean,结合Session Façade 模式。
PetStore 中EJB 的设计模式
34/34
ShoppingClientFacadeLocal
(f rom ejb)
AccountLocal
getStatus()
setStatus()
getCreditCard()
setCreditCard()
getContactInfo()
setContactInfo()
(f rom ejb)
CustomerLocal
getUserId()
getAccount()
getProfile()
(f rom ejb)
?? ShoppingClientFacadeLocalEJB,它是远程方法,供远程调用。
public class ShoppingClientFacadeLocalEJB implements SessionBean {
private ShoppingCartLocal cart = null;
private CustomerLocal customer = null;
/*
* Asume that the customer userId has been set
*/
//供远程调用,内部使用本地方法
public CustomerLocal getCustomer() throws FinderException {
try {
//使用本地调用,方法与远程不同
InitialContext ic = new InitialContext();
Object o = ic.lookup("java:comp/env/ejb/local/Customer");
//获得本地接口
CustomerLocalHome home =(CustomerLocalHome)o;
customer = home.findByPrimaryKey(userId);
} catch (javax.naming.NamingException nx) {
PetStore 中EJB 的设计模式
35/35
throw new GeneralFailureException("ShoppingClientFacade: failed to look up
name of customer: caught " + nx);
}
return customer;
}
}
2.7.4. PetStore 例子
在PetStore 中的EntityBean 都是使用的本地方法,在Session Facde 中调用本地接口。
见上面的例子。
2.8. CMR 模式
其实这也不算一种模式,它是在EJB2。0 中新增的重要特征。在IBM 的DevelpoerWorks
中有一篇教程介绍的非常详细。在PetStore 的实体Bean 中,大量的使用了它。所以我把它
作为一种模式,重点介绍它。在JB6.0 中建立这种关系非常容易,如果自己手写的话,需要
在web.xml 中增加关系。
2.8.1. 意图
您不必编写低级 JDBC 调用,并且不必编写代码来管理关系。它都内建在 EJB 框架中。关系
的接口直接通过大多数 EJB 开发者已经很熟悉的流行的 java.util.Collection 和
java.util.Set 构建。非常酷!
2.8.2. 动机
使系统简洁,方便开发。具体的好处需你仔细体会。
2.8.3. 结构
实际就是建立我们的在数据库中的关系。它包括1 对1,1 对多,多对多。我感觉最好大家
好好学习IBM 站点上的那篇文章。下图是使用JB6.0 建立的关系。
PetStore 中EJB 的设计模式
36/36
2.8.4. PetStore 中的例子
在petStore 例子
public abstract class CustomerEJB implements javax.ejb.EntityBean {
private EntityContext context = null;
// getters and setters for CMP fields
// CMR Fields
public abstract AccountLocal getAccount();
public abstract void setAccount(AccountLocal account);
public abstract ProfileLocal getProfile();
public abstract void setProfile(ProfileLocal profile);
}
ejb.jar
<relationships>
<ejb-relation>
<ejb-relation-name>Customer-Account</ejb-relation-name>
<ejb-relationship-role>
PetStore 中EJB 的设计模式
37/37
<ejb-relationship-role-name>CustomerEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>CustomerEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>account</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>AccountEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete />
<relationship-role-source>
<ejb-name>AccountEJB</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
</ejb-relation>
<ejb-relation>
<ejb-relation-name>Customer-Profile</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>CustomerEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>CustomerEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>profile</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>ProfileEJB</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete />
<relationship-role-source>
<ejb-name>ProfileEJB</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
</ejb-relation>
2.9. 业务代表模式
其实这种模式,就是GOF 的proxy 模式在ejb 中的应用。在<<J2EE 核心模式>>一书有详细
PetStore 中EJB 的设计模式
38/38
介绍。在petStore 的1.2.1 版本的例子很明显
2.9.1. 意图
使用业务代表来降低web 层和ejb 层之间的耦合,它隐藏了业务逻辑调用的细节,如ejb
的查找和访问的细节。其实客户端,首先调用业务代表,然后由他负责真正在调用ejb 层的
服务,就是proxy.。这种模式在GOF 中有详细的介绍,在JIVE 项目使用的也比较多。
改模式一般结合Session Façade 和ServiceLocator 模式使用,通常它和Session Façade 模式
存在一对一的关系,是因为如果在业务代表存在调用多个ejb,那么就会把这些关系转移到
session façade 中。
2.9.2. 动机
1. 降低web 层和ejb 层之间耦合
通过隐藏ejb 层的调用,如服务的查找等,由于只需要在业务代表一个地方进
行变化的管理和维护,所以实现起来更加容易。
2. 可以转化ejb 层的异常
业务代表可以把ejb 层的异常,转化会web 层的异常,如在petStore1.2.1 中的
例子把EstoreAppException 异常转化为GeneralFailureException
public class ShoppingClientControllerWebImpl implements java.io.Serializable {
public synchronized ShoppingCart getShoppingCartEJB() {
try {
//com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientController
sccEjb;
return sccEjb.getShoppingCart();
} catch (EStoreAppException ce) {
throw new GeneralFailureException(ce.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
}
3. 实现失效恢复和线程同步
如果遇到ejb 层服务的失效,业务代表可以自动恢复,而无需在调用处直接进
行恢复,特别是在多处调用,每个处都需进行处理,而这样可以集中在业务代
表处进行处理。
4. 向业务层提供更简单的,统一的接口
5. 提高系统性能
业务代表可以向web 层提供请求的缓冲机制,提高性能。例如可以缓存远程接
口,而不需每次都进行查找远程接口。
PetStore 中EJB 的设计模式
39/39
6. 引入代理层
业务代表被看作是在web 层和wjb 层之间的代理层,从而引入了复杂性,降低
了灵活性。有些开发者,这样增加了工作,同时它也带来了某些好处。具体是
否使用改模式,请开发人员进行衡量。(我们的项目就没有使用)
7. 隐藏远程性
2.9.3. 结构
2.9.4. PetStore 中的例子
在petStore1.2.1 中ShoppingClientControllerWebImpl 其实就是一个业务代表的例子。
public class ShoppingClientControllerWebImpl implements java.io.Serializable {
private com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientController sccEjb;
private HttpSession session;
public ShoppingClientControllerWebImpl() {
}
/**
* constructor for an HTTP client.
* @param the HTTP session object for a client
*/
public ShoppingClientControllerWebImpl(HttpSession session) {
this.session = session;
ModelManager mm =
(ModelManager)session.getAttribute(WebKeys.ModelManagerKey);
PetStore 中EJB 的设计模式
40/40
sccEjb = mm.getSCCEJB();
}
public synchronized ShoppingCart getShoppingCartEJB() {
try {
return sccEjb.getShoppingCart();
} catch (EStoreAppException ce) {
throw new GeneralFailureException(ce.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
public synchronized Customer getCustomerEJB() {
try {
return sccEjb.getCustomer();
} catch (EStoreAppException fe) {
throw new GeneralFailureException(fe.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
public synchronized ProfileMgr getProfileMgrEJB() {
try {
return sccEjb.getProfileMgr();
} catch (EStoreAppException fe) {
throw new GeneralFailureException(fe.getMessage());
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
public synchronized Collection handleEvent(EStoreEvent ese)
throws EStoreEventException {
try {
return sccEjb.handleEvent(ese);
} catch (RemoteException re) {
throw new GeneralFailureException(re.getMessage());
}
}
/**
* frees up all the resources associated with this controller and
PetStore 中EJB 的设计模式
41/41
* destroys itself.
*/
public synchronized void remove() {
// call ejb remove on self/shopping cart/etc.
try {
sccEjb.remove();
} catch(RemoveException re){
// ignore, after all its only a remove() call!
Debug.print(re);
} catch(RemoteException re){
// ignore, after all its only a remove() call!
Debug.print(re);
}
}
}
2.9.5. GOF 模式
2.1.4.18 Proxy 模式
?? 意图
为其他对象提供一种代理以控制对这个对象的访问。
?? 适用性
• 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模
式。下面是一 些可以使用P r o x y 模式常见情况:
1) 远程代理(Remote Proxy )为一个对象在不同的地址空间提供局部代表。
NEXTSTEP[Add94] 使用N X P r o x y 类实现了这一目的。Coplien[Cop92] 称这种
代理为“大使” (A m b a s s a d o r )。
2 )虚代理(Virtual Proxy )根据需要创建开销很大的对象。在动机一节描述的I m a
g e P r o x y 就是这样一种代理的例子。
3) 保护代理(Protection Proxy )控制对原始对象的访问。保护代理用于对象应该有
不同 的访问权限的时候。例如,在C h o i c e s 操作系统[ C I R M 9 3 ]中K e m e l P
r o x i e s 为操作系统对象提供 了访问保护。
4 )智能指引(Smart Reference )取代了简单的指针,它在访问对象时执行一些附加
操作。 它的典型用途包括:
• 对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(也称为S
m a r tP o i n t e r s[ E d e 9 2 ] )。
• 当第一次引用一个持久对象时,将它装入内存。
• 在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。
结构
PetStore 中EJB 的设计模式
42/42
3. EJB 模式关系
正如Christopher Alexander 的评论,模式不是孤立存在的,需要其他模式的结合側更具
有伟力。现在我们讨论以上所罗列各种模式之间的关系。
业务代表
Session Facade
ServiceLocator
值对象组装器
Page-by-Page
Iterator
复合实体模式Value Object模式
CRM模式Local模式DAO模式
Fast-
Lane
Reader
模式
首先是在web 层与ejb 层的结合层(Proxy)由业务代表实现,它一般与SessionFacade
是一对一的关系,当然它一般会使用ServiceLocator 模式,来查找和定位ejb。客户端一般
使用业务代表来调用业务逻辑,而不是直接进行调用。为了简化接口,我们使用SessionFacade
模式,来封装复杂的业务逻辑,通过SessionFacade 模式来调用其他的ejb,一般其他被调用
者,一般使用CRM 和Local 模式,这样可以提高效率。为了提高接口的粗粒度,我们一般
使用Value Object 模式,复合实体,以及值对象组装器模式。有时接口的需要值对象的列表,
我们又使用Page-By-Page 模式,来缓存大量的之对象。还有一种景况,就是为了提高效率,
不使用ejb,而是直接连接数据库,就是Fast-Lane-Reader。
• 业务代表模式
• ServiceLocator 模式
• SessionFacade 模式
PetStore 中EJB 的设计模式
43/43
• Value Object 模式
• Page-By-Page 模式
• 复合实体
• CRM 模式

4. 相关的资料
1. sun 站点
2. IBM DevelpoerWorks
3. 《J2EE 模式》
4. 《设计模式-可复用面向对象的软件的基础》
5. http://www.javaunion.org/http://www.chinajavaworld.com/ 站点的一些网友作品。
5. 总结

posted on 2007-03-09 02:17 金家寶 阅读(439) 评论(0)  编辑  收藏 所属分类: J2EE概念理论性文摘


只有注册用户登录后才能发表评论。


网站导航: