浅谈 Facade 模式
Facade 模式
所谓 Facade 模式,是一个可以让事情变得有点头绪的好东西。
一个 Facade 肯定是一位某方面的“行家”,例如数据库操作。它对来自上层的请求屏蔽了具体的业务逻辑细节,任何程序需要对数据库进行 CRUD 操作时,只需要告诉 Facade 层“我要做什么”,而 Facade 层则知道“到哪里去做”,于是它根据请求的具体内容,调用相应的底层模块(在那里解决“到底怎样做”的问题)。进行具体的操作。当它从底层模块中取得所需的数据后,再将结果返回给上层程序。
Facade 具体应用
一个 Facade 模块可以针对一种需求,处理来自各方面的请求。例如在一个用户注册模块中,当前的需求描述为“只要用户名没有冲突,就允许注册”。因为这是一种很宽松的注册策略,所以我们不妨把相应的 Facade 类称为 LenientFacade。
这个 Facade 类首先根据用户输入的信息构造出一个 UserBean,然后检测该用户名是否已被占用。如果未被占用,就调用 DAO 执行增加记录操作,否则就抛出一个“用户名已存在”的异常。
public class LenientFacade {
public int insertUser (ActionForm actionForm) throws ... {
int row;
UserForm userForm = (UserForm) actionForm;
// 根据formBean生成UserBean
UserBean userBean = new UserBean();
BeanUtils.copyProperties(userBean, userForm);
// 执行数据库插入操作,首先查看该用户是否存在。
setUserDAO(new UserDAOibatis());
UserBean user = dao.loadUserByUsername(userBean.getUsername());
if (user != null) {
// 同名用户已存在,抛出一个自定义的异常 UserAlreadyExistException。
throw new UserAlreadyExistException("User already exist.");
}
row = dao.insertUser(userBean);
return row; // 返回该用户的id(AUTO_INCREMENT)。
}
public void setUserDAO (UserDAO dao) {
this.dao = dao;
}
private UserDAO dao;
}
在某一时期,可能因为各种政策的原因,网站需要对注册用户进行更为严格的审核。所以我们需要 Facade 具有不同的业务逻辑。不妨把负责这种更严格的注册过程的 Facade 类称为 StrictFacade。
StrictFacade 除了验证用户名是否可用外,还要验证用户的国籍、年龄、学历等等一大堆事情。下面是伪代码:
public class StrictFacade {
public int insertUser (ActionForm actionForm) throws ... {
... //和前面相同的代码
// 执行数据库插入操作,首先查看该用户是否存在。
setUserDAO(new UserDAOibatis());
UserBean user = dao.loadUserByUsername(userBean.getUsername());
if (user != null) {
// 同名用户已存在,抛出一个自定义的异常 UserAlreadyExistException。
throw new UserAlreadyExistException("User already exist.");
}
try {
// 许多许多更严格的审查
// 许多许多更严格的审查
}
catch (... ) {
...
throw 五花八门的异常
}
row = dao.insertUser(userBean);
return row; // 返回该用户的id(AUTO_INCREMENT)。
}
public void setUserDAO (UserDAO dao) {
this.dao = dao;
}
private UserDAO dao;
}
执行更加严格的注册过程,并不意味着原有的“宽松式”注册就没有用了。网站可能需要随时根据情况在两种策略之间切换。显然,每次切换注册过程就停掉服务器,重新编译 Facade 层的代码,然后再重启服务器,会让老板和所有的用户疯掉!
这时,使用灵活的抽象工厂模式就可以解决这个问题。
.
结合抽象工厂模式的 Facade 模式
抽象工厂模式可以根据初始参数的不同,生产出适应各种需求的具体实现类。我们可以设计两种工厂,一种是 LenientFacadeFactory,另一种是 StrictFacadeFactory,二者分别负责生产“宽松式”和“严格式”的 Facade。
这两个工厂都继承自他们的父类 —— 一个抽象的 FacadeFactory。这个抽象的 Factory 使用一个静态方法返回具体的 Factory 类,并且为它的子类们定义了获得Facade的get方法:public abstract Facade getFacade();,所有继承了抽象工厂的具体工厂类,都要负责为其调用者返回一个实际可用的 Facade。
抽象的 Facade 工厂代码如下:
public abstract class FacadeFactory {
public static FacadeFactory getInstance(int facadeFactoryType) {
switch (facadeFactoryType) {
case LENIENT:
return new LenientFacadeFactory();
case STRICT:
return new StrictFacadeFactory();
default:
return null;
}
}
public abstract Facade getFacade();
public static final int LENIENT = 0;
public static final int STRICT = 1;
}
下面是 LenientFacadeFactory 的代码,Strict 版本的与其类似。
public class LenientFacadeFactory extends FacadeFactory {
public Facade getFacade() {
return new LenientFacade();
}
}
通过这段代码,我们就可以得到本文一开始的那段代码中的 LenientFacade 了。
在程序(在Strut中应该是一个Action)中的具体调用方法是:
int facadeType = FacadeFactory.LENIENT;
FacadeFactory factory = FacadeFactory.getInstance(facadeType);
Facade facade = factory.getFacade();
try {
row = facade.insertUser(userForm);
}
catch (...) {
...
}
这样做的好处很明显:Servlet (或具体为一个Action)不需要去产生出一个具体的 Facade,所有的方法调用都是建立在统一的接口之上。当我们需要一个不同类型的 Facade 的时候,只需要调整上面代码中第一行的 facadeType 变量,就能产生出相应的 Facade。因此实现了 Controller 层和 Model 层的松耦合。
.
通过配置初始化参数实现“更松的”耦合
首先声明!这并不是一个很好解决方案,这仅仅是为了复习巩固所学的知识而自创的办法。
上面的代码中,问题没有得到根本的解决,因为那个代表着 facade 类型的 facadeType 变量仍旧被硬编码在程序中了。不过这个问题并不难解决,只要考虑到 ActionServlet 的本质是一个 Servlet,我们就可以通过为该 Servlet 设置一个初始化参数解决它。
可以在 web.xml 配置描述符中,为 ActionServlet 增加一个初始化参数:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>facadeType</param-name>
<param-value>LENIENT</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
然后,我们在程序中就可以读取这个初始化参数,进而得到适用的 FacadeFactory 了。
String facadeType = this.getServlet().getInitParameter("facadeType");
浅谈 Facade 模式相关推荐
- 浅谈软件研发模式中瀑布模型、迭代模型、敏捷模型
要比较模型的区别,首先说说什么叫软件开发.软件开发是一项包括版本计划.需求捕捉.需求分析.设计到代码编写.调试.维护的一系列过程.软件开发不仅仅是编程.而对于软件研发(Reserch and Deve ...
- 浅谈Facade外观模式
一. 基本概念 有些人可能炒过股票,但其实大部分人都不太懂,这种没有足够了解证券知识的情况下做股票是很容易亏钱的,刚开始炒股肯定都会想,如果有个懂行的帮帮手就好,其实基金就是个好帮手,支付宝里就有许多 ...
- 浅谈严格模式和混杂模式
一,严格模式和混杂模式的定义: 通俗来说: 严格模式是浏览器根据w3c的规范来解析代码: 混杂模式是浏览器根据自己的规范来解析代码(很明显:无规矩不成方圆,这种混杂模式会产生一些浏览器兼容问题). 二 ...
- 浅谈开发模式及架构发展
一.传统开发模式 传统的开发模式基本一般是重服务端的开发方式,大部分工作都在服务端执行,然后返回到客户端(通常是HTML).以Asp.net MVC为例,如下图: #1 根据请求的路由定位到对应的Co ...
- Android应用开发—浅谈MVX模式
MVX模式的文章太多了,这里不会再重述,关键我还不太懂,本文会从自己的一些思考,分析下MVX的分离思想,先占个坑! Android应用架构这篇文章最后讲到: Activity和Fragment变得非常 ...
- iOS:个人浅谈工厂模式
一.什么是工厂方法? 正式的解释是:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行.工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的策略,很好 ...
- STM32——浅谈睡眠模式、停机模式、待机模式
若要理解低功耗,则先要说一下STM32的事件和中断 事件是中断的触发源,开放了对应的中断屏蔽位,则事件可以触发相应的中断.在STM32中,中断与事件不是等价的,一个中断肯定对应一个事件,但一个事件不一 ...
- 操作系统:浅谈实模式,保护模式与长模式
学习了操作系统的实模式.保护模式与长模式,此文作为回顾. x86 CPU 在第一次加电和每次 reset 后,都会自动进入实模式,要想进入保护模式,就需要程序员写代码实现从实模式切换到保护模式. 一. ...
- 为什么工厂模式是华而不实的——浅谈工厂模式的利与弊
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17428923 说明:博主虚心接受大家的抨击,批评,指正 前言 我一直想介绍下 ...
最新文章
- R语言绘制堆叠面积图
- DWRUtil的方法使用说明
- Redis单机版本框架
- 【学习笔记】mysql多实例安装
- SQL Server Reporting Services(简称SSRS)
- HDFS API编程
- EMC混合云解决方案Enterprise Hybrid Cloud升级
- ROS学习记录:基于Python的ROS话题消息编程
- NG2-我们创建一个可复用的服务来调用英雄的数据
- 线性时间选择算法-《数据结构》(结合例题讲解)
- win10便签常驻桌面_小巧免费的桌面便签工具分享
- 阵列卡PERCH330_H730配置手册
- 如何解决请将磁盘插入U盘(F)的情况
- 飞机大战学习心得(Dev-C++)
- 10首现代诗歌欣赏:什么是孤独
- html中switch的控件,自己实现简单的switch开关插件
- 世界上最漂亮城市夜景
- JAV spi 和扩展方式
- 会导致电脑蓝屏的wav文件原因未知 log whea logger 17 realtek alc269系统播放音频崩溃
- 关于Criteria