一起谈模式,ok?(50分)

  • 主题发起人 wildhorseli
  • 开始时间
W

wildhorseli

Unregistered / Unconfirmed
GUEST, unregistred user!
Design Patters 四人帮的书,买了两年了,反复也懂或不懂的读了几边了
,一点小小的感受,希望与大家分享。
模式我的感觉就是程式的解决方案,最大限度的适应外界不确定的变化。

低藕合和复用效果应该是想要的一个效果,在delphi的系统架构中,我们
经常会用到哪些呢?
创建型模式:
我们更多的是用了Factory 和 Builder(组合对象),尤其以Factory
为重,而我们的操作主要目的是为了界面的统一。Builder对象的构建与它的
表示分离,这是我们值得学习的地方。
Singleton也有时用到,就是保证该实例是唯一的,比如你要保证某
个系统某个窗体排他性。
行为型模式:
Chain of Responsebilty :就是孩子的事情不做,就要老爷子去处理了
,类似于win的消息机制,如果孩子有处理消息的需求,就让他处理。
Command:菜单处理了,或TActionList类中,不同需求,参数化改变,
使得客户数据改变。当然这里有类似代理的感觉。要是和备注搭配实现撤销的
功能是在我们的设计中很有好处的。
InterPreter:我们自己的契约,然后我们自己的表达翻译方式。说白了
就是我们规定工程中的某些我们有意义的集合或常量,以我们的实际要求显示
和追踪,然后翻译成我们的流程或所需。
Iterator:类似与数组或链表的功能,同时绑定相应的我们需要的实例。
实现查询特定的需求,或返回特定的元件。当然和visitor差别不是很大,vsi
tor对于特定的绑定,或修改特定绑定的操作,使之协调。
Mediator:用一个对象封装一系列对象交互。使藕合松散,不需要之间直
接打交道。porpxy只为某个对象代理,给出的相当于个接口,而Mediator是多
个对象的调解。
Strategy:就是封装你系统用的函数集合。
Observer,State:我个人认为这两个搭配使用效果更好,他们相当于mvc
中的C,某个实例变化,观察到状态,然后改变他们的视图。
比如:我的一个系统中有多个相同的树型控件,并且在不同的界面,开始
的做法是我们每到一个页面就要进行刷新,可是多层架构数据处理切换会带来
速度和时间上的不爽。我们需要一个观察者,发现数据变化,我们就会去更新
。但问题又出来了,如果多个客户端,而别的客户端数据发生改变又如何呢?
所以我们就对应一个特定的树状态检测配合观察者实现要求效果。
结构型模式:
老板让我干活了,有空再写了!
各位身体健康!工作倍爽!
 
转贴
J2EE中的设计模式
什么是Design Patten?
简单来说,Design Patten 就是一个常用的方案。 在我们的开发过程中,经常会遇到一些相同或者相近的问题,每次我们都会去寻找一个新的解决方法,为了节省时间提高效率,我们提供一些能够解决这些常见问题的,被证实可行的方案,构成一个统一的资源库。
一个Design Patten描述了一个被证实可行的方案。这些方案非常普通,是有完整定义的最常用的模式。 这些模式可以被重用,有良好的伸缩性,而这些Design Patten的优势将在设计J2EE应用时得到体现。
1.Model-View-Controller
a.问题
如果开发一个企业级应用,只需要一种客户端的话,那么一切都非常容易解决。但真实情况是,我们必须面对运行在各种设备上客户端,象PDA,WAP浏览器以及运行在桌面上的浏览器,我们不得不开发不同的应用程序来处理来自不同客户端的请求。数据访问与现实将混淆在一起,可能会出现重复的数据访问,导致整个开发周期没有必要的延长。
b. 建议的解决方法
Model-View-Controller (MVC) 开发模式被证明是有效的处理方法之一。它可以分离数据访问和数据表现。你可以开发一个有伸缩性的,便于扩展的控制器,来维护整个流程。如图1所示为整个模式的结构。MVC模式可以被映射到多层企业级的J2EE应用上。
§ 所有的企业数据以及商业逻辑可以作为模式。
§ 视图可以通过模式访问数据,并根据客户端的要求来显示数据。视图必须保证当模式改变的时候,数据显示也必须同时改变。
§ 控制器用来结合模式和视图,把客户端来的请求转换成模式能够理解并执行的请求,并且根据请求以及执行结果来决定下一次显示那一个视图。
根据以上的逻辑,你可以象这样建立一个应用:
§ 应用的商业逻辑由MVC中的模式也就是EJB来表现。模式必须处理由控制器传递过来的对数据的访问请求。
§ 多个页面组成了MVC中的视图,这些视图必须随模式一起更新。
§ 控制器是一系列接收用户动作的对象,他们把用户的请求转换成模式可理解的请求,并决定显示那一个页面当模式处理完请求后。

图 1
c. 要点
§ MVC结构适用于那些多用户的,可扩展的,可维护的,具有很高交互性的系统。
§ MVC可以很好的表达用户的交互和系统模式。
§ 很方便的用多个视图来显示多套数据,是系统很方便的支持其他新的客户端类型。
§ 代码重复达到最低。
§ 由于分离了模式中的流控制和数据表现,可以分清开发者的责任,另外,也可以加快产品推向市场的时间。
2. Front Controller
a.问题
MVC给出了一个整个应用的松散的耦合架构。现在来看一下这样一个经常发生的情况。在某一个应用中,用户看到的视图和他所做的操作密切相关。这是一些具有高度交互性的页面,而这些页面之间含有高度的依赖性。在没有任何模式的时候,这个应用只是一个许多独立的页面的集合,维护和扩展变得异常困难。
§ 当一个页面移动后,其他含有这个页面链接的文件,都必须修改。
§ 当有一系列页面需要口令保护时,许多配置文件需要修改,或者页面需要包含新的标记。
§ 当一个页面需要一个新的表示层时,页面中的标记要被重新安排。
当这个系统变得复杂时,这些问题将变得更糟。如果用MVC来解决的话,就变成一个如何管理控制器和视图之间交互的问题。
b.建议的解决方法
前台控制模式可以解决这个问题。这个模式中,所有的请求都被传送到一个对象中。这个主要的对象将处理所有的请求,决定以后显示那一个视图,以及实现必要的安全需求。对于把视图显示以及其他功能实现集中到一个主要的对象中,将使修改变得很容易,对应用的修改,可以在所有视图中反映出来。
c.要点
§ 这个模式对于需要在多个含有动态数据的页面之间进行复杂导航的系统来说,是很有效的。
§ 这个模式对于要在所有页面中都包含模板,转换等的应用来说,也是很有效的。
§ 由于视图的选择集中在前端控制器上,因此,视图的导航变得更加容易理解和便于配置。
§ 视图重用和变更会更加容易。
§ 视图之间的复杂交互,使得控制器变得复杂。从而,当应用发展的时候,控制器将变得难以维护。不过,大部分情况下可以用XML映射来解决。
§ 实现应用要求的安全性检验变得很简单。
§ 这个模式不适合小型的,只显示静态内容的应用。
d.样例
§ RequestMappings.xml 文件映射了传入的请求,处理器以及下一个页面。
<request-mappings>
<url-mapping url="/request1"
useRequestHandler="true"
requiresSecurityCheck="true" nextScreen="screen2.jsp">
<request-handler-class>
com.blah1.blah2.blah3.request1Handler
</request-handler-class>
</url-mapping>
<!-- other requests and their corresponding mappings -->
</request-mappings>
以上这个文件是控制器的指定配置,控制器的代码如下:
§ FrontControllerImpl.java 利用上面的XML实现了控制器
// all required imports
// exceptions to be caught appropriately wherever applicable
public class FrontControllerImpl extends HttpServlet {
// all required declarations, definitions
private HashMap requestMappings;
public void init() {
// load the mappings from XML file into the hashmap
}
public voiddo
Post(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
do
Get(request, response);
}
public voiddo
Get(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String currentPage= request.getPathInfo();
// get all mapping info for "currentPage" from the hashmap
// if "securityCheckRequired = true",do
the security check
// if "useRequestHandler = true", pass on the incoming request to the specified handler
// forward the results to the given "nextScreen"
}
}
用这种方法实现的控制器将很容易维护,当应用有新的变动的时候,只要修改XML文件就能解决了。前台控制模式将使在视图和控制器之前有复杂交互的J2EE应用变得简单。
3. Session Fa?ade
a. 问题
前台控制给出了一个基于MVC的,能有效管理用户与J2EE应用之间进行的复杂交互。这个模式可以使处理页面的现实顺序和用户的并发请求变得简单。并且使增加和改变页面现实变得更加容易。
另外一个常见的问题是,当EJB或者业务逻辑发生变化的时候,应用的客户端也必须随之改变。我们来看一下这个问题。
一般来说,为了表现一个账户中的用户,我们使用一个业务逻辑来表示账户中的信息,象用户名和口令,再用一个EJB来管理用户的个人信息,象爱好,语言等。当要创建一个新的账号或者修改一个已经存在的账号时,必须访问包含账号信息的EJB,读取个人信息,修改并且保存,这样的一个流程。
当然,这只是一个非常简单的例子,实际情况可能比这个复杂的多,象查看用户定制了哪些服务,检验客户信用卡的有效性,存放订单等。在这个案例中,为了实现一个完整的流程,客户端必须访问账户EJB来完成一系列适当的工作。下面的例子显示了一个Servlet客户端如何来控制一个用户订单。
A servlet thatdo
es the workflow required for placing an order
// all required imports;
// exceptions to be caught appropriately wherever applicable;
// This servlet assumes that for placing an order the account and
// credit status of the customer has to be checked before getting the
// approval and committing the order. For simplicity, the EJBs that
// represent the business logic of account, credit status etc are
// not listed
public class OrderHandlingServlet extends HttpServlet {
// all required declarations, definitions
public void init() {
// all inits requireddo
ne here
}
public voiddo
Post(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// other logic as required
// Get reference to the required EJBs
InitialContext ctxt = new InitialContext();
Object obj = ctxt.lookup("java:comp/env/ejb/UserAccount");
UserAccountHome acctHome = (UserAccountHome)
PortableRemoteObject.narrow(obj, UserAccountHome.class);
UserAccount acct = acctHome.create();
obj = ctxt.lookup("java:comp/env/ejb/CreditCheck");
CreditCheckHome creditCheckHome = (CreditCheckHome)
PortableRemoteObject.narrow(obj, CreditCheckHome.class);
CreditCheck credit = creditCheckHome.create();
obj = ctxt.lookup("java:comp/env/ejb/Approvals");
ApprovalsHome apprHome = (ApprovalsHome)
PortableRemoteObject.narrow(obj, ApprovalsHome.class);
Approvals appr = apprHome.create();
obj = ctxt.lookup("java:comp/env/ejb/CommitOrder");
CommitOrderHome orderHome = (CommitOrderHome)
PortableRemoteObject.narrow(obj, CommitOrderHome.class);
CommitOrder order = orderHome.create();
// Acquire the customer ID and order details;
// Nowdo
the required workflow to place the order
int result = acct.checkStatus(customerId);
if(result != OK) {
// stop further steps
}
result = credit.checkCreditWorth(customerId, currentOrder);
if(result != OK) {
// stop further steps
}
result = appr.getApprovals(customerId, currentOrder);
if(result != OK) {
// stop further steps
}
// Everything OK;
place the order
result = order.placeOrder(customerId, currentOrder);
//do
further processing as required
}
}
以上的代码显示了一个单个的客户端。如果这个应用支持多种客户端的话,必须为每一个客户端制定一种处理方法来完成工作流程。如果有一个EJB的实现流程需要改变的话,那么所有的参与这个流程的客户端都需要改变。如果不同的EJB之间的交互需要改变的话,所有的客户端都必须知道这一点,如果流程中需要增加一个新的步骤的话,所有的客户端也必须随之修改。
这样一来,EJB和客户端之间的改变变得非常困难。客户端必须对每个EJB分开进行访问,致使网络速度变慢。同样,应用越复杂,麻烦越大。
b. 建议的解决方法
解决这个问题的方法是,把客户端和他们使用的EJB分割开。建议适用Session Fa?ade模式。这个模式通过一个Session Bean,为一系列的EJB提供统一的接口来实现流程。事实上,当客户端只是使用这个接口来触发流程。这样,所有关于EJB实现流程所需要的改变,都和客户端无关。
看下面这个例子。这段代码用来控制与客户相关的订单的处理方法。
// All imports required
// Exception handling not shown in the sample code
public class OrderSessionFacade implements SessionBean {
// all EJB specific methods like ejbCreate defined here
// Here is the business method thatdo
es the workflow
// required when a customer places a new order
public int placeOrder(String customerId, Details orderDetails)
throws RemoteException {
// Get reference to the required EJBs
InitialContext ctxt = new InitialContext();
Object obj = ctxt.lookup("java:comp/env/ejb/UserAccount");
UserAccountHome acctHome = (UserAccountHome)
PortableRemoteObject.narrow(obj, UserAccountHome.class);
UserAccount acct = acctHome.create();
obj = ctxt.lookup("java:comp/env/ejb/CreditCheck");
CreditCheckHome creditCheckHome = (CreditCheckHome)
PortableRemoteObject.narrow(obj, CreditCheckHome.class);
CreditCheck credit = creditCheckHome.create();
obj = ctxt.lookup("java:comp/env/ejb/Approvals");
ApprovalsHome apprHome = (ApprovalsHome)
PortableRemoteObject.narrow(obj, ApprovalsHome.class);
Approvals appr = apprHome.create();
obj = ctxt.lookup("java:comp/env/ejb/CommitOrder");
CommitOrderHome orderHome = (CommitOrderHome)
PortableRemoteObject.narrow(obj, CommitOrderHome.class);
CommitOrder order = orderHome.create();
// Nowdo
the required workflow to place the order
int result = acct.checkStatus(customerId);
if(result != OK) {
// stop further steps
}
result = credit.checkCreditWorth(customerId, currentOrder);
if(result != OK) {
// stop further steps
}
result = appr.getApprovals(customerId, currentOrder);
if(result != OK) {
// stop further steps
}
// Everything OK;
place the order
int orderId = order.placeOrder(customerId, currentOrder);
//do
other processing required
return(orderId);
}
// Implement other workflows for other order related functionalities (like
// updating an existing order, canceling an existing order etc.) in a
// similar way
}
在模式允许的情况下,Servlet代码将很容易实现。
// all required imports
// exceptions to be caught appropriately wherever applicable
public class OrderHandlingServlet extends HttpServlet {
// all required declarations, definitions
public void init() {
// all inits requireddo
ne here
}
public voiddo
Post(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// other logic as required
// Get reference to the session facade
InitialContext ctxt = new InitialContext();
Object obj = ctxt.lookup("java:comp/env/ejb/OrderSessionFacade");
OrderSessionFacadeHome facadeHome = (OrderSessionFacadeHome)
PortableRemoteObject.narrow(obj, OrderSessionFacadeHome.class);
OrderSessionFacade facade = facadeHome.create();
// trigger the order workflow
int orderId = facade.placeOrder(customerId, currentOrder);
//do
further processing as required
}
}
就象上面显示的,客户端的逻辑变得非常简单。流程中的任何改变只要修改模式中的一处地方就可以了。客户端可以仍旧使用原来的接口,而不必做任何修改。同样,这个模式可以用来响应其他处理器的流程处理。这让你能用同样的模式来处理不同客户端的不同流程。在这个例子中,模式提供了很好的伸缩性和可维护性。
c. 要点
§ 既然这种模式不涉及到数据访问,就应该用Session Bean来实现。
§ 对于用简单接口来实现复杂EJB的子系统来说,是一个理想的选择。
§ 这个模式不适用于无流程处理的应用。
§ 这个模式可以减少客户端于EJB之间的通信和依赖。
§ 所有和EJB有关的交互,都有同一个Session Bean来控制,可以减少客户端对EJB的误用。
§ 这个模式可以使支持多类型客户端变得更容易。
§ 可以减少网络数据传递。
§ 所有的服务器端的实现细节都对客户端隐藏,在改变发生后,客户端不用重新发布。
§ 这个模式可以同样看成一个集中处理器来处理所有的安全或日志纪录。
4.Data Access Object
a.问题
目前为止,你看到的模型都是用来构建可伸缩的,易于维护的J2EE应用。这些模式尽可能的把应用在多个层上来实现。但是,还有一点必须强调:EJB的数据表现。它们包括象EJB这样的数据库语言。如果数据库有改变的话,相应的SQL也必须改变,而EJB也必须随之更新。
这些常见问题就是:访问数据源的代码与EJB结合在一起,这样致使代码很难维护。看以下的代码。
An EJB that has SQL code embedded in it
// all imports required
// exceptions not handled in the sample code
public class UserAccountEJB implements EntityBean {
// All EJB methods like ejbCreate, ejbRemove go here
// Business methods start here
public UserDetails getUserDetails(String userId) {
// A simple query for this example
String query = "SELECT id, name, phone FROM userdetails WHERE name = " + userId;
InitialContext ic = new InitialContext();
datasource = (DataSource)ic.lookup("java:comp/env/jdbc/DataSource");
Connection dbConnection = datasource.getConnection();
Statement stmt = dbConnection.createStatement();
ResultSet result = stmt.executeQuery(queryStr);
// other processing like creation of UserDetails object
result.close();
stmt.close();
dbConnection.close();
return(details);
}
}
b. 建议的解决方法
为了解决这个问题,从而让你能很方便的修改你的数据访问。建议使用DAO模式。这个模式把数据访问逻辑从EJB中拿出来放入独立的接口中。结果是EJB保留自己的业务逻辑方法,在需要数据的时候,通过DAO来访问数据库。这样的模式,在要求修改数据访问的时候,只要更新DAO的对象就可以了。看以下的代码。
A Data Access Object that encapsulates all data resource access code
// All required imports
// Exception handling code not listed below for simplicity
public class UserAccountDAO {
private transient Connection dbConnection = null;
public UserAccountDAO() {}
public UserDetails getUserDetails(String userId) {
// A simple query for this example
String query = "SELECT id, name, phone FROM userdetails WHERE name = " + userId;
InitialContext ic = new InitialContext();
datasource = (DataSource)ic.lookup("java:comp/env/jdbc/DataSource");
Connection dbConnection = datasource.getConnection();
Statement stmt = dbConnection.createStatement();
ResultSet result = stmt.executeQuery(queryStr);
// other processing like creation of UserDetails object
result.close();
stmt.close();
dbConnection.close();
return(details);
}
// Other data access / modification methods pertaining to the UserAccountEJB
}
现在你有了一个DAO对象,利用这个对象你可以访问数据。再看以下的代码。
An EJB that uses a DAO
// all imports required
// exceptions not handled in the sample code
public class UserAccountEJB implements EntityBean {
// All EJB methods like ejbCreate, ejbRemove go here
// Business methods start here
public UserDetails getUserDetails(String userId) {
// other processing as required
UserAccountDAO dao = new UserAccountDAO();
UserDetails details = dao.getUserDetails(userId);
// other processing as required
return(details);
}
}
任何数据源的修改只要更新DAO就可以解决了。另外,为了支持应用能够支持多个不同的数据源类型,你可以开发多个DAO来实现,并在EJB的发布环境中指定这些数据源类型。在一般情况下,EJB可以通过一个Factory对象来得到DAO。用这种方法实现的应用,可以很容易的改变它的数据源类型。
c. 要点
§ 这个模式分离了业务逻辑和数据访问逻辑。
§ 这种模式特别适用于BMP。过一段时间,这种方式同样可以移植到CMP中。
§ DAOs可以在发布的时候选择数据源类型。
§ DAOs增强了应用的可伸缩性,因为数据源改变变得很容易。
§ DAOs对数据访问没有任何限制,甚至可以访问XML数据。
§ 使用这个模式将导致增加一些额外的对象,并在一定程度上增加应用的复杂性。
 
cao,你转这个烂贴干嘛!你自己说说理解的东西就可以了。
 
好文章!
 
春三月,和Borland专家--刘艺相约上海!
大家好:
 “一年之计在于春”,春天是定目标、打基础关键时刻!
无论你的目标是加薪,成为项目经理,还是让自己的技术水平更上一层楼,
都需要不断地学习,而与高手的交流,仿佛是站在巨人的肩上:站得高,看得远,助力你迅速成为Delphi高手!
应中国项目经理网邀请,Borland专家--刘艺老师将于这个三月来到上海
给大家做<<UML与DELPHI模型驱动开发>>的培训,机会难得!请热爱Delphi的朋友请抓紧时间报名!
届时将会有众多Delphi高手光临现场!热烈的现场讨论以及众多Delphi高手的面对面交流讲师本次培训的特色之一!
在温暖的三月,刘艺与众多Delphi高手与大家相约上海!

中国项目经理网相关培训链接:
[公告]阳春三月,和刘艺老师面对面讨论UML和Delphi面向对象开发!
http://www.china-pm.net/dispbbs.asp?boardID=22&amp;ID=5&amp;page=1
[公告]uml与delphi模型驱动开发课程介绍
http://www.china-pm.net/dispbbs.asp?boardID=22&amp;ID=21&amp;page=1
报名表
http://www.china-pm.net/dispbbs.asp?boardID=22&amp;ID=35&amp;page=1
中国项目经理网
2004-02-14
 
顶部