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

代码的“门面”——模式系列谈之Facade模式

阅读更多

看到“门面”这个词,大家一定都觉得很熟悉。不错,这个词正是借用了我们日常生活中的“门面”的概念。日常生活中的“门面”,正是我们买东西的地方。因此可以这么说,“门面”就是这么一个地方,它们跟各种商品的生产商打交道,收集商品后,再卖给我们。换句话说,如果没有“门面”,我们将不得不直接跟各种各样的生产商买商品;而有了“门面”,我们要买东西,直接跟“门面”打交道就可以了。

Facade模式正是这样一个“门面”:我们本来需要与后台的多个类或者接口打交道,而Facade模式是客户端和后台之间插入一个中间层——门面,这个门面跟后台的多个类或接口打交道,而客户端只需要跟门面打交道即可。

使用Facade模式可以说是后台设计和编码人员的一个必备素质。我不止碰到过一个这样的后台开发人员,他们认为只要把后台功能完成了就万事大吉,而没有站在后台使用者的角度来看一看自己写出来的代码。其实,我们写出来的后台代码是要给别人使用的,所以我们提供给使用者的接口要越简单越好,这不单是对使用者好,同时对开发者也是好处多多的,至少你的接口简单了,你和使用者的交流就容易了。

而Facade模式中的Facade类正是这样一个用户接口,它和后台中的多个类产生依赖关系,而后台的客户类则只跟Facade类产生依赖关系。为什么要这么做?其中的原因十分简单:后台的开发者熟悉他自己开发的各个类,也就容易解决和多个类的依赖关系,而后台的使用者则不太熟悉后台的各个类,不容易处理和它们之间的依赖;因此,后台的开发者自己在Facade类中解决了与后台多个类之间的依赖,后台的使用者只需要处理和Facade类的依赖即可。

好了,闲话少说。我们下面就以几个具体的例子来看一看Facade模式是怎么使用的。实际编程中,能使用到Facade模式的情况有很多,以下就分两种情况来具体说一说Facade模式的使用。可能还会有其他的情况,大家在实践中也可以加以补充。

第一种情况,客户类要使用的功能分布在多个类中,这些类可能相互之间没有什么关系;客户在使用后台的时候,必须先初始化要使用到的功能所在的类,然后才能使用。这时候,适合将这些功能集中在一个Facade类里,还可以替用户做一些初始化的工作,以减轻用户的负担
例如,以商店为例。假如商店里出售三种商品:衣服、电脑和手机。这三种商品都是由各自的生产厂商卖出的,如下:
public class CoatFactory
{
public Coat saleCoat()
{
……
return coat;
}
……
}

然后是电脑的厂家类:

public class ComputerFactory
{
public Computer saleComputer()
{
……
return computer;
}
……
}

最后是手机商类:

public class MobileFactory
{
public Mobile saleMobile()
{
……
return mobile;
}
……
}


如果没有商店,我们就不得不分别跟各自的生产商打交道,如下:

//买衣服
CoatFactory coatFactory = new CoatFactory();
coatFactory.saleCoat();
//买电脑
ComputerFactory computerFactory = new ComputerFactory();
computerFactory.saleComputer();
//买手机
MobileFactory mobileFactory = new MobileFactory();
mobileFactory.saleMobile();


对我们顾客来说,和这么多的厂家类打交道,这显然是够麻烦的。


这样,我们就需要创建一个商店类了,让商店类和这些厂家打交道,我们只和商店类打交道即可,如下:

public class Store
{
public Coat saleCoat()
{
CoatFactory coatFactory = new CoatFactory();
return coatFactory.saleCoat();
}
public Computer saleComputer()
{
ComputerFactory computerFactory = new ComputerFactory();
return computerFactory.saleComputer();
}
public Mobile saleMobile()
{
MobileFactory mobileFactory = new MobileFactory();
return mobileFactory.saleMobile();
}
}


好了,现在我们要买东西,不用去跟那么多的厂家类打交道了。

Store store =new Store();
//买衣服
store.saleCoat();
//买电脑
store.saleComputer();
//买手机
store.saleMobile();


呵呵,这样对我们客户类来说,是不是简单多了。

第二种情况客户要完成的某个功能,可能需要调用后台的多个类才能实现,这时候特别要使用Facade模式。不然,会给客户的调用带来很大的麻烦。请看下面的例子。

我经常看到后台编码人员,强迫它们的使用者写出如下的代码:

……
String xmlString = null;
int result = 0;
try
{
xmlString = gdSizeChart.buildDataXML(incBean);


String path = "D:/Eclipse3.0/workspace/PLMSuite/AppWeb/PM/productSpecification/gridfile.xml";
File f = new File(path);
PrintWriter out = new PrintWriter(new FileWriter(f));
out.print(xmlString);
out.close();
System.out.println("\r\n\r\n sumaryAction" + xmlString + "\r\n\r\n");
request.setAttribute("xmlString", xmlString);
}
catch(Exception ex)
{
ex.printStackTrace();
}


这段代码前面即省略号省略掉的一部分是客户类调用后台的一部分代码,是一个相对独立的功能。后面这一部分也是一个相对独立的功能,而后台代码设计人员却把这个功能留给客户类自己来实现。

我就很怀疑,让客户类做这么多事情,到底要你的后台做什么?你还不如直接把所有的事情都给客户类做了得了。因为,你后台做了一半,剩下的一部分给客户类做,客户类根本就不明白怎么回事,或者说他不清楚你的思路,这样做下去更加困难。可能这点逻辑对你来说,很简单。但使用者不明白你的思路啊,他不知道来龙去脉,怎么往下写?

如果在这里有一个Facade类,让它来做不该由客户类来做的事,是不是简单多了呢?如下是一个Facade类:

public class Facade
{
public static void doAll(PE_MeasTableExdBean incBean, HttpServletRequest request)
{
……
request.setAttribute(“xmlString”,Facade.getFromOut(incBean));
}
private static String getFromOut(PE_MeasTableExdBean incBean)
{
try
{
xmlString = gdSizeChart.buildDataXML(incBean);


String path = "D:/Eclipse3.0/workspace/PLMSuite/AppWeb/PM/productSpecification/gridfile.xml";
File f = new File(path);
PrintWriter out = new PrintWriter(new FileWriter(f));
out.print(xmlString);
out.close();
System.out.println("\r\n\r\n sumaryAction" + xmlString + "\r\n\r\n");
return xmlString;
}
catch(Exception ex)
{
ex.printStackTrace();
return null;
}
}
}

那么客户类的调用就是下面的样子:

Facade.doAll(incBean,request);


这样,客户是不是轻松多了?值得注意的是,Facade类中的getFromOut方法其实不应该在Facade类中,本文为了简单起见而放在了这个类中,对Facade类来说是不符合单一职责原则的。

最后总结一下第二种情况的模式。后台为实现某一个功能有如下类:

public class ClassA
{
public void doA()
{
……
}
……
}
public class ClassB
{
public void doB()
{
……
}
……
}
public class ClassC
{
public void doC()
{
……
}
……
}

如果客户类需要这样调用:

……
ClassA a = new ClassA();
a.doA();
ClassB b = new ClassB();
b.doB();
ClassC c = new ClassC();
c.doC();
……


那么就适合做一个Facade类,来替客户类来完成上述的功能,如下:

public class Facade
{
public void doAll()
{
ClassA a = new ClassA();
a.doA();
ClassB b = new ClassB();
b.doB();
ClassC c = new ClassC();
c.doC();
}
}


则客户类的调用如下:

……
Facade Facade = new Facade();
Facade.doAll();

分享到:
评论

相关推荐

    C++设计模式原理与实战视频课

    C++设计模式原理与实战视频课 1-1 课程介绍 1-2 导论UML和设计模式导论 2-1 简单工厂方法的定义场景与实现-针对接口编程的设计思想剖析 ...3-2 门面(外观)模式Facade的定义、场景与实用工程技术:LOD

    C#23种设计模式_示例源代码及PDF

    幸好相机有 Facade 设 计模式,把相 机调整到自动档,只要对准目标按快门就行了,一切由相机自动调整,这样 MM 也可以用 这个相机给我拍张照片了。 门面模式: 门面模式提供一个 门面模式 外部与一个子系统的通信...

    Java设计模式经典搞笑珍藏版

    #### 八、门面模式(Facade Pattern) 门面模式为子系统中的一组接口提供一个一致的界面,门面模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 #### 九、适配器模式(Adapter Pattern) 适配器模式...

    java设计模式学习笔记

    ### Java设计模式学习笔记——外观模式(Facade Pattern) #### 概述 设计模式是软件工程领域中一种解决常见问题的可复用解决方案。在Java开发过程中,掌握设计模式能够帮助开发者更好地组织代码结构,提高代码的...

    java 设计模式-个人总结

    - **定义**:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 - **应用场景**:为一个复杂的子系统或一组服务提供一个简单、统一的接口。 - **优点**...

    C#设计模式大全

    #### 门面(Facade)模式 门面模式是一个结构型设计模式,它为子系统中的一组接口提供一个统一的更高层接口。 - **结构**:包含子系统类、子系统模块以及门面类。 - **实现**:门面类封装了子系统中的复杂交互。 -...

    设计模式之外观模式

    ### 设计模式之外观模式详解 #### 一、引言 在软件开发过程中,随着系统的不断扩展和功能的增加,可能会出现系统结构复杂、接口众多的情况。为了简化系统的使用方式,提高系统的可维护性和可扩展性,外观模式...

    门面1

    在IT行业中,"门面1"的标题可能指的是一个基于Java编程语言实现的软件设计模式——门面(Facade)模式。门面模式是一种结构型设计模式,它为复杂的子系统提供了一个简单的接口,使得客户端无需了解子系统内部的复杂...

    IntelliJ IDEA基于SSM框架整合开发模板带用户增删改查分页功能源代码

    `Slf4j`(Simple Logging Facade for Java)是一个日志门面,提供统一的日志API,允许用户在部署时选择不同的日志实现,如logback、log4j等。`logback`则是Slf4j的一个具体实现,提供高性能且灵活的日志记录功能。 ...

    十个 log4j 转移到LogBack的理由

    3. **无缝集成 SLF4J**:SLF4J(Simple Logging Facade for Java)是一个日志门面,允许用户在运行时选择不同的日志实现。LogBack 作为 SLF4J 的原生实现,提供了更紧密的集成和更高的性能。 4. **SLF4J 桥接器**:...

    Laravel开发-laravel-debugbar

    为了帮助开发者实现这些需求,Laravel 提供了一个强大的工具——Laravel Debugbar(laravel-debugbar)。这个扩展库能够集成到 Laravel 应用中,为开发者提供一个直观的界面来查看和分析运行时的信息。 **Laravel ...

Global site tag (gtag.js) - Google Analytics