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 模式相关推荐

  1. 浅谈软件研发模式中瀑布模型、迭代模型、敏捷模型

    要比较模型的区别,首先说说什么叫软件开发.软件开发是一项包括版本计划.需求捕捉.需求分析.设计到代码编写.调试.维护的一系列过程.软件开发不仅仅是编程.而对于软件研发(Reserch and Deve ...

  2. 浅谈Facade外观模式

    一. 基本概念 有些人可能炒过股票,但其实大部分人都不太懂,这种没有足够了解证券知识的情况下做股票是很容易亏钱的,刚开始炒股肯定都会想,如果有个懂行的帮帮手就好,其实基金就是个好帮手,支付宝里就有许多 ...

  3. 浅谈严格模式和混杂模式

    一,严格模式和混杂模式的定义: 通俗来说: 严格模式是浏览器根据w3c的规范来解析代码: 混杂模式是浏览器根据自己的规范来解析代码(很明显:无规矩不成方圆,这种混杂模式会产生一些浏览器兼容问题). 二 ...

  4. 浅谈开发模式及架构发展

    一.传统开发模式 传统的开发模式基本一般是重服务端的开发方式,大部分工作都在服务端执行,然后返回到客户端(通常是HTML).以Asp.net MVC为例,如下图: #1 根据请求的路由定位到对应的Co ...

  5. Android应用开发—浅谈MVX模式

    MVX模式的文章太多了,这里不会再重述,关键我还不太懂,本文会从自己的一些思考,分析下MVX的分离思想,先占个坑! Android应用架构这篇文章最后讲到: Activity和Fragment变得非常 ...

  6. iOS:个人浅谈工厂模式

    一.什么是工厂方法? 正式的解释是:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行.工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的策略,很好 ...

  7. STM32——浅谈睡眠模式、停机模式、待机模式

    若要理解低功耗,则先要说一下STM32的事件和中断 事件是中断的触发源,开放了对应的中断屏蔽位,则事件可以触发相应的中断.在STM32中,中断与事件不是等价的,一个中断肯定对应一个事件,但一个事件不一 ...

  8. 操作系统:浅谈实模式,保护模式与长模式

    学习了操作系统的实模式.保护模式与长模式,此文作为回顾. x86 CPU 在第一次加电和每次 reset 后,都会自动进入实模式,要想进入保护模式,就需要程序员写代码实现从实模式切换到保护模式. 一. ...

  9. 为什么工厂模式是华而不实的——浅谈工厂模式的利与弊

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17428923 说明:博主虚心接受大家的抨击,批评,指正 前言 我一直想介绍下 ...

最新文章

  1. R语言绘制堆叠面积图
  2. DWRUtil的方法使用说明
  3. Redis单机版本框架
  4. 【学习笔记】mysql多实例安装
  5. SQL Server Reporting Services(简称SSRS)
  6. HDFS API编程
  7. EMC混合云解决方案Enterprise Hybrid Cloud升级
  8. ROS学习记录:基于Python的ROS话题消息编程
  9. NG2-我们创建一个可复用的服务来调用英雄的数据
  10. 线性时间选择算法-《数据结构》(结合例题讲解)
  11. win10便签常驻桌面_小巧免费的桌面便签工具分享
  12. 阵列卡PERCH330_H730配置手册
  13. 如何解决请将磁盘插入U盘(F)的情况
  14. 飞机大战学习心得(Dev-C++)
  15. 10首现代诗歌欣赏:什么是孤独
  16. html中switch的控件,自己实现简单的switch开关插件
  17. 世界上最漂亮城市夜景
  18. JAV spi 和扩展方式
  19. 会导致电脑蓝屏的wav文件原因未知 log whea logger 17 realtek alc269系统播放音频崩溃
  20. 关于Criteria

热门文章

  1. Linux计划任务介绍
  2. Ansible 部署的时候提示错误 SSH password instead
  3. matlab矩阵输出txt文件中,matlab怎么把矩阵输出到txt
  4. 代理网易云音乐,免费听歌与下载
  5. 网易游戏测试工程师面试小记
  6. u盘linux系统安装文件,使用U盘安装LINUX系统
  7. 财务分析与决策——利润表
  8. mysql数据库的配置
  9. sci影响因子小于1计算机,单位入编要求两篇SCI,影响因子大于1.0就可以,请问难吗?...
  10. 模型调优(Tuning)(一)