博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈 Facade 模式
阅读量:4069 次
发布时间:2019-05-25

本文共 6970 字,大约阅读时间需要 23 分钟。

<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><servlet><br> <servlet-name>action</servlet-name><br> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class><br> <init-param><br> <param-name>config</param-name><br> <param-value>/WEB-INF/struts-config.xml</param-value><br> </init-param><br><strong> <init-param><br> <param-name>facadeType</param-name><br> <param-value>LENIENT</param-value><br> </init-param></strong><br> <load-on-startup>0</load-on-startup><br></servlet><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>

转载地址:http://bcaji.baihongyu.com/

你可能感兴趣的文章
利用负载均衡优化和加速HTTP应用
查看>>
消息队列设计精要
查看>>
分布式缓存负载均衡负载均衡的缓存处理:虚拟节点对一致性hash的改进
查看>>
分布式存储系统设计(1)—— 系统架构
查看>>
MySQL数据库的高可用方案总结
查看>>
常用排序算法总结(一) 比较算法总结
查看>>
SSH原理与运用
查看>>
SIGN UP BEC2
查看>>
S3C2440中对LED驱动电路的理解
查看>>
《天亮了》韩红
查看>>
Windows CE下USB摄像头驱动开发(以OV511为例,附带全部源代码以及讲解) [转]
查看>>
出现( linker command failed with exit code 1)错误总结
查看>>
iOS开发中一些常见的并行处理
查看>>
iOS获取手机的Mac地址
查看>>
ios7.1发布企业证书测试包的问题
查看>>
如何自定义iOS中的控件
查看>>
iOS 开发百问
查看>>
Mac环境下svn的使用
查看>>
github简单使用教程
查看>>
如何高效利用GitHub
查看>>