`
simgsg
  • 浏览: 96129 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

浅谈 Facade 模式

 
阅读更多
<p><strong><span style="">Facade 模式</span></strong> </p>
<p><strong></strong></p>
<p>所谓 Facade 模式,是一个可以让事情变得有点头绪的好东西。 </p>
<p> </p>
<p>一个 Facade 肯定是一位某方面的“行家”,例如数据库操作。它对来自上层的请求屏蔽了具体的业务逻辑细节,任何程序需要对数据库进行 CRUD 操作时,只需要告诉 Facade 层“<strong>我要做什么</strong>”,而 Facade 层则知道“<strong>到哪里去做</strong>”,于是它根据请求的具体内容,调用相应的底层模块(在那里解决“<strong>到底怎样做</strong>”的问题)。进行具体的操作。当它从底层模块中取得所需的数据后,再将结果返回给上层程序。 </p>
<p><img src="http://www.jdon.com/designpatterns/images/facade.jpg" border="0" alt="" width="500" height="232"></p>
<p><strong><span style="">Facade 具体应用</span></strong> </p>
<p><strong></strong></p>
<p>一个 Facade 模块可以针对一种需求,处理来自各方面的请求。例如在一个用户注册模块中,当前的需求描述为“只要用户名没有冲突,就允许注册”。因为这是一种很宽松的注册策略,所以我们不妨把相应的 Facade 类称为 LenientFacade。 </p>
<p>这个 Facade 类首先根据用户输入的信息构造出一个 UserBean,然后检测该用户名是否已被占用。如果未被占用,就调用 DAO 执行增加记录操作,否则就抛出一个“用户名已存在”的异常。 </p>
<p> </p>
<div style="padding-bottom: 1px; background-color: #ffffcc; padding-left: 4px; padding-right: 4px; padding-top: 1px; border: 1px solid;"> 
<p><span style="font-family: Courier New;"><strong>public class LenientFacade</strong> {<br> public int insertUser (ActionForm actionForm) throws ... {<br> int row;<br> UserForm userForm = (UserForm) actionForm;<br><br> // 根据formBean生成UserBean<br> UserBean userBean = new UserBean();<br> BeanUtils.copyProperties(userBean, userForm);<br><br><br> // 执行数据库插入操作,首先查看该用户是否存在。<br> setUserDAO(new UserDAOibatis());<br> UserBean user = dao.loadUserByUsername(userBean.getUsername());<br> if (user != null) {<br> // 同名用户已存在,抛出一个自定义的异常 UserAlreadyExistException。<br> throw new UserAlreadyExistException("User already exist.");<br> }<br> row = dao.insertUser(userBean);<br> return row; // 返回该用户的id(AUTO_INCREMENT)。<br> }<br><br> public void setUserDAO (UserDAO dao) {<br> this.dao = dao;<br> }<br><br> private UserDAO dao;<br>}</span> </p>
<p>  </p>
</div>
<p> </p>
<p>在某一时期,可能因为各种政策的原因,网站需要对注册用户进行更为严格的审核。所以我们需要 Facade 具有不同的业务逻辑。不妨把负责这种更严格的注册过程的 Facade 类称为 StrictFacade。 </p>
<p> </p>
<p>StrictFacade 除了验证用户名是否可用外,还要验证用户的国籍、年龄、学历等等一大堆事情。下面是伪代码: </p>
<p>  </p>
<div style="background-color: #ffffcc; border: 1px solid;"> 
<p><span style="font-family: Courier New;"><strong>public class StrictFacade</strong> {<br> public int insertUser (ActionForm actionForm) throws ... {<br><br> ... //和前面相同的代码<br><br> // 执行数据库插入操作,首先查看该用户是否存在。<br> setUserDAO(new UserDAOibatis());<br> UserBean user = dao.loadUserByUsername(userBean.getUsername());<br> if (user != null) {<br> // 同名用户已存在,抛出一个自定义的异常 UserAlreadyExistException。<br> throw new UserAlreadyExistException("User already exist.");<br> }<br><br> try {<br><strong>// 许多许多更严格的审查<br> // 许多许多更严格的审查</strong><br> }<br> catch (... ) {<br> ...<br> throw 五花八门的异常 <br> }</span> </p>
<p><span style="font-family: Courier New;"><br> row = dao.insertUser(userBean);<br> return row; // 返回该用户的id(AUTO_INCREMENT)。<br> }<br><br> public void setUserDAO (UserDAO dao) {<br> this.dao = dao;<br> }<br><br> private UserDAO dao;<br>}</span> </p>
<p>  </p>
</div>
<p>  </p>
<p>执行更加严格的注册过程,并不意味着原有的“宽松式”注册就没有用了。<strong>网站可能需要随时根据情况在两种策略之间切换</strong>。显然,每次切换注册过程就停掉服务器,重新编译 Facade 层的代码,然后再重启服务器,会让老板和所有的用户疯掉! </p>
<p> </p>
<p>这时,使用灵活的抽象工厂模式就可以解决这个问题。 </p>
<p><span style="color: #c0c0c0;">.</span> </p>
<p><strong><span style="">结合抽象工厂模式的 Facade 模式</span></strong> </p>
<p><strong></strong></p>
<p>抽象工厂模式可以根据初始参数的不同,生产出适应各种需求的具体实现类。我们可以设计两种工厂,一种是 LenientFacadeFactory,另一种是 StrictFacadeFactory,二者分别负责生产“宽松式”和“严格式”的 Facade。 </p>
<p> </p>
<p>这两个工厂都继承自他们的父类 —— 一个抽象的 FacadeFactory。这个抽象的 Factory 使用一个静态方法返回具体的 Factory 类,并且为它的子类们定义了获得Facade的get方法:<span style="font-family: Courier New;">public abstract Facade getFacade();</span>,所有继承了抽象工厂的具体工厂类,都要负责为其调用者返回一个实际可用的 Facade。 </p>
<p> </p>
<p>抽象的 Facade 工厂代码如下: </p>
<p> </p>
<div style="background-color: #ffffcc; border: #000000 1px solid;"> 
<p><span style="font-family: Courier New;"><strong>public abstract class FacadeFactory</strong> {<br><br> public static FacadeFactory getInstance(int facadeFactoryType) {<br> switch (facadeFactoryType) {<br> case LENIENT:<br> return new LenientFacadeFactory();<br> case STRICT:<br> return new StrictFacadeFactory();<br> default:<br> return null;<br> }<br> }<br><br> public abstract Facade getFacade();<br><br> public static final int LENIENT = 0;<br> public static final int STRICT = 1;<br>}</span> </p>
<p>  </p>
</div>
<p> </p>
<p>下面是 LenientFacadeFactory 的代码,Strict 版本的与其类似。 </p>
<p> </p>
<div style="padding-bottom: 1px; background-color: #ffffcc; padding-left: 4px; padding-right: 4px; padding-top: 1px; border: #000000 1px solid;"> 
<p><span style="font-family: Courier New;"><strong>public class LenientFacadeFactory extends FacadeFactory</strong> {<br><br> public Facade getFacade() {<br> return new LenientFacade();<br> }<br>}</span><br>  </p>
</div>
<p> </p>
<p>通过这段代码,我们就可以得到本文一开始的那段代码中的 LenientFacade 了。 </p>
<p> </p>
<p>在程序(在Strut中应该是一个Action)中的<strong>具体调用方法</strong>是: </p>
<p> </p>
<div style="padding-bottom: 1px; background-color: #ffffcc; padding-left: 4px; padding-right: 4px; padding-top: 1px; border: 1px solid;">
<span style="font-family: Courier New;"><br>int facadeType = FacadeFactory.LENIENT;<br><br>FacadeFactory factory = FacadeFactory.getInstance(facadeType);<br>Facade facade = factory.getFacade();<br><br>try {<br> row = facade.insertUser(userForm);<br>}<br>catch (...) {<br> ...<br>}<br> </span> </div>
<p> </p>
<p><strong>这样做的好处很明显:</strong>Servlet (或具体为一个Action)不需要去产生出一个具体的 Facade,所有的方法调用都是<strong>建立在统一的接口之上</strong>。当我们需要一个不同类型的 Facade 的时候,只需要调整上面代码中第一行的 facadeType 变量,就能产生出相应的 Facade。因此实现了 Controller 层和 Model 层的<strong>松耦合</strong>。 </p>
<p> </p>
<p><span style="color: #c0c0c0;">.</span> </p>
<p><strong><span style="">通过配置初始化参数实现“更松的”耦合</span></strong> </p>
<p><strong></strong></p>
<p>首先声明!这并不是一个很好解决方案,这仅仅是为了复习巩固所学的知识而自创的办法。 </p>
<p> </p>
<p>上面的代码中,问题没有得到根本的解决,因为那个代表着 facade 类型的 facadeType 变量仍旧被硬编码在程序中了。不过这个问题并不难解决,只要考虑到 <strong>ActionServlet 的本质是一个 Servlet</strong>,我们就可以通过为该 Servlet 设置一个初始化参数解决它。 </p>
<p> </p>
<p>可以在 web.xml 配置描述符中,为 ActionServlet 增加一个初始化参数: </p>
<p> </p>
<div style="padding-bottom: 1px; background-color: #ffffcc; padding-left: 4px; padding-right: 4px; padding-top: 1px; border: 1px solid;">
<span style="font-family: Courier New;"><br>&lt;servlet&gt;<br> &lt;servlet-name&gt;action&lt;/servlet-name&gt;<br> &lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;/servlet-class&gt;<br> &lt;init-param&gt;<br> &lt;param-name&gt;config&lt;/param-name&gt;<br> &lt;param-value&gt;/WEB-INF/struts-config.xml&lt;/param-value&gt;<br> &lt;/init-param&gt;<br><strong> &lt;init-param&gt;<br> &lt;param-name&gt;facadeType&lt;/param-name&gt;<br> &lt;param-value&gt;LENIENT&lt;/param-value&gt;<br> &lt;/init-param&gt;</strong><br> &lt;load-on-startup&gt;0&lt;/load-on-startup&gt;<br>&lt;/servlet&gt;<br></span> </div>
<p>然后,我们在程序中就可以读取这个初始化参数,进而得到适用的 FacadeFactory 了。 </p>
<p> </p>
<div style="padding-bottom: 1px; background-color: #ffffcc; padding-left: 4px; padding-right: 4px; padding-top: 1px; border: 1px solid;">
<span style="font-family: Courier New;"><br>String facadeType = this.getServlet().getInitParameter("facadeType");<br> </span> </div>
<p>  </p>
分享到:
评论

相关推荐

    设计模式1,FACADE模式,Adapter

    本文将深入探讨FACADE模式、Adapter模式以及Singleton和Proxy模式的基本概念、应用场景和关键要素。 首先,FACADE(外观)模式是一种接口型模式,它的主要作用是为复杂的子系统提供一个简单的接口,使得客户端无需...

    设计模式之门面模式(Facade模式)

    设计模式之门面模式(Facade模式),介绍门面模式,实际例子分析,代码讲解等

    C++ Facade模式

    **C++ Facade模式** Facade模式,又称为外观模式,是设计模式中的一种结构型模式。在软件工程中,它为子系统提供了一个统一的入口,简化了客户端对复杂子系统的访问,使得客户端无需了解子系统内部的具体实现细节。...

    Facade模式

    **Facade模式** Facade模式是一种设计模式,它提供了一个统一的接口,用来访问子系统中的一组接口。这个统一的接口使得客户端不必了解子系统组件的内部细节,简化了客户端与复杂系统之间的交互。在软件工程中,当一...

    java实现的简单的应用facade模式范例

    **Java实现的简单应用:Facade模式范例** Facade模式,也称为门面模式,是一种结构型设计模式,它提供了一个统一的接口,用于与复杂的子系统进行交互。这个模式简化了客户端与子系统之间的交互,使得客户端只需要...

    C#面向对象设计模式纵横谈\11 结构型模式Facade外观模式.zip

    在这里与各位分享本人从网络上下载的C#面向对象设计模式纵横谈系列视频,共有25节,除了第一节需要各位贡献一点资源分以作为对本人上传资源的回馈,后面的其他资源均不需要资源分。敬请期待。 这是第11节:结构型...

    FACADE模式

    **外观(Facade)模式**是一种结构型设计模式,它的主要目的是提供一个统一的接口,用于客户端访问复杂的子系统。在大型软件系统中,通常由多个模块或子系统组成,每个子系统都有自己的功能,而客户端可能需要与这些...

    Ajax中使用Facade外观模式的Eclipse版本的Demo

    **Ajax与Facade模式** 在Web开发中,Ajax(Asynchronous JavaScript and XML)技术允许我们创建交互性更强、响应更快的网页。它通过在后台与服务器进行少量数据交换,实现了页面的部分更新,而无需刷新整个页面。...

    Command和Facade设计模式

    在软件设计模式的世界里,`Command`(命令)和`Facade`(外观)模式是非常重要的两种设计模式。它们分别服务于不同的目的,但都是为了提高代码的可读性、可维护性和灵活性。 `Command`模式是一种行为设计模式,它将...

    设计模式之外观模式 facade

    外观模式(Facade Pattern)是设计模式中的一种结构型模式,主要目的是为了解决复杂的系统接口问题,提供一个简单的统一入口,使得客户端可以更方便地使用系统。在Java中,外观模式通常用来隐藏系统的复杂性,对外只...

    facade设计模式

    **外观(Facade)设计模式**是一种结构型设计模式,它为复杂的系统或子系统提供一个统一、简洁的接口,使得客户端可以更容易地与其交互。在软件工程中,当一个系统包含多个子系统或者组件,而这些子系统之间相互依赖...

    设计模式之Facade

    eclipse工程文件 包含代码 有助理解 门面(Facade)模式 &lt;br&gt;外部与一个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。 &lt;br&gt;医院的例子 &lt;br&gt;用一个例子进行说明,如果把医院...

    java 设计模式 Facade外观模式 Simple Factory 简单工厂模式

    在Java中,当你有一个复杂的子系统,而你希望客户端代码能够以一种更简洁、更易于理解的方式来与之交互时,就可以使用Facade模式。这个模式通过创建一个新类(外观类),将子系统中的一系列接口聚合到一起,客户端只...

    设计模式之外观模式(Facade Pattern)

    **外观模式(Facade Pattern)**是一种结构型设计模式,它主要解决的是复杂系统或子系统对外暴露一个简单统一的接口,使得客户端无需关心内部复杂的交互细节。这种模式在实际开发中广泛应用,尤其在大型项目中,它能...

    C#面向对象设计模式纵横谈(11):Facade 外观模式(结构型模式) (Level 300)

    **外观模式(Facade Pattern)**是面向对象设计模式中的一种结构型模式,它提供了一个统一的接口,用于访问子系统中的各个部分。在C#编程中,外观模式可以帮助我们简化复杂的系统接口,使得客户端代码与复杂的内部...

Global site tag (gtag.js) - Google Analytics