研磨设计模式之外观模式(Facade)(解决方案)

2019-03-28 21:59|来源: 网络

3.2  解决方案

3.2.1  外观模式来解决

       用来解决上述问题的一个合理的解决方案就是外观模式。那么什么是外观模式呢?

(1)外观模式定义

       这里先对两个词进行一下说明,一个是界面,一个是接口。


  • 界面

       一提到界面,估计很多朋友的第一反应就是图形界面(GUI)。其实在这里提到的界面,主要指的是从一个组件外部来看这个组件,能够看到什么,这就是这个组件的界面,也就是所说的外观。

       比如:你从一个类外部来看这个类,那么这个类的public方法就是这个类的外观,因为你从类外部来看这个类,就能看到这些。

       再比如:你从一个模块外部来看这个模块,那么这个模块对外的接口就是这个模块的外观,因为你就只能看到这些接口,其它的模块内部实现的东西是被接口封装隔离了的。


  • 接口

       一提到接口,做Java的朋友的第一反应就是interface。其实在这里提到的接口,主要是指的外部和内部交互的这么一个通道,通常是指的一些方法,可以是类的方法,也可以是interface的方法。也就是说,这里说的接口,并不等价于interface,也有可能是一个类。

(2)应用外观模式来解决的思路

      仔细分析上面的问题,客户端想要操作更简单点,那就根据客户端的需要来给客户端定义一个简单的接口,然后让客户端调用这个接口,剩下的事情就不用客户端管,这样客户端就变得简单了。

       当然,这里所说的接口就是客户端和被访问的系统之间的一个通道,并不一定是指Java的interface。事实上,这里所说的接口,在外观模式里面,通常指的是类,这个类被称为“外观”。

       外观模式就是通过引入这么一个外观类,在这个类里面定义客户端想要的简单的方法,然后在这些方法的实现里面,由外观类再去分别调用内部的多个模块来实现功能,从而让客户端变得简单,这样一来,客户端就只需要和外观类交互就可以了。

3.2.2  模式结构和说明

外观模式的结构如图3.4所示:

图3.4  外观模式结构示意图

Facade

       定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块,从而把客户的请求代理给适当的子系统对象。

模块:

       接受Facade对象的委派,真正实现功能,各个模块之间可能有交互。

       但是请注意,Facade对象知道各个模块,但是各个模块不应该知道Facade对象。

3.2.3  外观模式示例代码

      由于外观模式的结构图过于抽象,因此把它稍稍具体点,假设子系统内有三个模块,分别是AModule、BModule和CModule,它们分别有一个示意的方法,那么此时示例的整体结构如图3.5所示:

图3.5  外观模式示例的整体结构示意图

       还是来看看代码示例,会比较清楚。


(1)首先定义A模块的接口,A模块对外提供功能方法,从抽象的高度去看,可以是任意的功能方法,示例代码如下:

/**

* A模块的接口

*/

public interface AModuleApi {

   /**

    * 示意方法,A模块对外的一个功能方法

    */

   public void testA();

}


(2)实现A模块的接口,  简单示范一下,示例代码如下:

public class AModuleImpl implements AModuleApi{

   public void testA() {

      System.out.println("现在在A模块里面操作testA方法");

   }

}


(3)同理定义和实现B模块、C模块,先看B模块的接口定义,示例代码如下:

public interface BModuleApi {

   public void testB();

}

 

B模块的实现示意,示例代码如下:

public class BModuleImpl implements BModuleApi{

   public void testB() {

      System.out.println("现在在B模块里面操作testB方法");

   }

}


C模块的接口定义,示例代码如下:

public interface CModuleApi {

   public void testC();

}

   

C模块的实现示意,示例代码如下:

public class CModuleImpl implements CModuleApi{

   public void testC() {

      System.out.println("现在在C模块里面操作testC方法");

   }

}


(4)定义外观对象,示例代码如下:

/**

* 外观对象

*/

public class Facade {

   /**

    * 示意方法,满足客户需要的功能

    */

   public void test(){

      //在内部实现的时候,可能会调用到内部的多个模块

      AModuleApi a = new AModuleImpl();

      a.testA();

      BModuleApi b = new BModuleImpl();

      b.testB();

      CModuleApi c = new CModuleImpl();

      c.testC();

   }

}


(5)客户端如何使用呢,直接使用外观对象就可以了,示例代码如下:

public class Client {

   public static void main(String[] args) {

      //使用Facade

      new Facade().test();

   }

}


运行结果如下:

现在在A模块里面操作testA方法

现在在B模块里面操作testB方法

现在在C模块里面操作testC方法


3.2.4  使用外观模式重写示例

      要使用外观模式重写前面的示例,其实非常简单,只要添加一个Facade的对象,然后在里面实现客户端需要的功能就可以了。


(1)新添加一个Facade对象,示例代码如下:

/**

* 代码生成子系统的外观对象

*/

public class Facade {

   /**

    * 客户端需要的,一个简单的调用代码生成的功能

    */

   public void generate(){

      new Presentation().generate();

      new Business().generate();

      new DAO().generate();

   }

}


(2)其它的定义和实现都没有变化,这里就不去赘述了


(3)看看此时的客户端怎么实现,不再需要客户端去调用子系统内部的多个模块,直接使用外观对象就可以了,示例代码如下:

public class Client {

   public static void main(String[] args) {

       //使用Facade

      new Facade().generate();

   }

}

      去运行看看,是否能正确地实现功能。


       如同上面讲述的例子,Facade类其实相当于A、B、C模块的外观界面,Facade类也被称为A、B、C模块对外的接口,有了这个Facade类,那么客户端就不需要知道系统内部的实现细节,甚至客户端都不需要知道A、B、C模块的存在,客户端只需要跟Facade类交互就好了,从而更好的实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易的使用系统。


本文链接:研磨设计模式之外观模式(Facade)(解决方案),转自:http://sishuok.com/forum/blogPost/list/5063.html

相关问答

更多

设计模式是对个别问题的解决方案?j2ee

设计模式是解决某一类具有共性的问题的解决方法,是前人经验的总结,或者叫捷径,根据这样的模式去解决问题就能够正确、完整的解决,否则,虽然采用其他的方式也能解决,但是会走“弯路”,不是目前最优的路径,所以才有了设计模式。 1、工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。 2、建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部 ...

什么是立面设计模式?(What is the facade design pattern?)

设计模式是解决重复问题的常用方式。 所有设计模式中的类只是正常类。 重要的是如何组织结构,以及如何共同努力以最佳方式解决给定的问题。 Facade设计模式简化了复杂系统的界面; 因为它通常由组成复杂系统的子系统的所有类组成。 门面将用户屏蔽系统的复杂细节,并为其提供easy to use的simplified view 。 它还将使用系统的代码与子系统的细节decouples ,以便稍后修改系统。 http://www.dofactory.com/Patterns/PatternFacade.as ...

有一个设计模式来命名这个解决方案?(There is a Design Pattern to name this solution?)

这是strategy设计模式的一个示例,此外,您可以创建一个abstract factory来创建特定的国家/地区电话格式化程序,而不会分散应用程序的所有代码的复杂性。 This is an example for the strategydesign pattern, in addition you can create an abstract factory to create specific country phone formatters without scattering the c ...

外观,代理,适配器和装饰设计模式之间的区别?(Difference between the Facade, Proxy, Adapter and Decorator design patterns? [closed])

适配器将给定的类/对象适配到新的接口。 在前者的情况下,通常采用多重继承。 在后一种情况下,对象被一个符合适配器对象包裹并传递。 我们在这里解决的问题是不兼容的接口 。 Facade更像是一个复杂的功能集的简单网关。 您为客户制作一个黑盒子,以减少担心,即使界面更简单 。 代理提供与代理类相同的界面,通常会自己做一些内务管理。 (所以,而不是制作一个重型对象X多个副本,您可以制作一个轻量级代理P副本,而后者又会根据需要管理X并转换您的呼叫。)您正在解决客户端不必管理重型和/或复杂的对象 。 装饰器 ...

外观和中介设计模式之间的区别?(Difference between Facade and Mediator Design pattern?)

以下代码段在设计模式中看起来很相似,但我感到困惑。 我认为你看到了两种模式的组成方面。 Facade链接到子系统的各种现有类,以添加一些简化子系统使用的典型功能。 在您引用的示例代码中, ShapeMaker提供了便于制作形状的服务。 调解员与需要合作的各种同事进行联系,以尽量减少同事之间对彼此的了解。 最大限度地减少知识有减少同事之间的耦合(他们只知道调解员)和增加他们的凝聚力(他们通常不需要担心,因为他们不知道更大的图片)的副作用。 在这两种模式中,集中式课程都承担着处理与其相关类别的复杂性的 ...

应用程序外观模式的最佳实践(Best practice for application facade pattern)

好吧,一旦将子系统封装为对象并为客户端提供所有业务对象和服务的聚合接口,Facade就非常适合SOA架构。 它还减少了架构中的耦合。 我认为您的方法并不重,不会影响系统的可扩展性。 Well, Facade is highly adequate for SOA architectures, once it encapsulates a subsystem as an object and provides an aggregated interface for all business objec ...

“门面设计模式”中有超过1个门面类?(More than 1 facade class in 'facade design pattern'?)

外观基本上是一种方便的功能分组。 如果存在多个这样的分组,您肯定可以制作多个外观。 请注意,使用依赖注入模式时,使用Facade模式远比以前少得多。 A facade is basically a convenient grouping of functionality. If multiple such groupings exist you may certainly make multiple facades. Please note that when using dependency i ...

门面设计模式和紧密耦合(Facade design pattern and close coupling)

在某种程度上你编写了你的例子,是的,它将紧密地结合你的代码。 主要是由于new关键字对你的依赖关系起着glue作用。 请记住,Facade模式不会阻止您创建紧密耦合的依赖项或代码。 使用它的主要目的是使您的软件组件更易于使用,更易读和可维护,并且最后但并非最不可测试的更多。 如果要避免紧密耦合,则需要在Facade类中传递抽象依赖项: public class Facade { private readonly ISystemA subsystemA; private readonly ISy ...

使用Singleton设计模式实现解决方案的建议(Suggestions for implementing a solution using Singleton design pattern)

您将无法“自动”将静态调用委派给模块。 即使调用不是静态的,如你所说,Java也不支持多重继承。 选项1: 让您的主Configuration类提供将实例返回到模块的静态方法。 每当您想要读取配置条目时,首先获取模块实例,然后查询条目本身: Configuration.getDatabaseConfiguration().getServerName(); 此方法的优点是,您可以非常清楚地指定了您的配置的哪个部分。 如果您只使用Configuration.getServerName() ,则无法确 ...

只读接口模式和外观模式有什么区别?(What is the difference between the read-only interface pattern and the facade pattern?)

Facade模式的主要目的不是使您的接口不可变。 来自维基百科 : 外观是一个对象, 它为更大的代码体提供了简化的接口 ,例如类库。 门面可以: 使软件库更易于使用,理解和测试,因为外观具有方便的常用任务方法; 出于同样的原因,使库更具可读性; 减少外部代码对库内部工作的依赖性,因为大多数代码使用外观,从而允许更灵活地开发系统; 使用一个设计良好的API(根据任务需要)包装设计不佳的API集合。 外墙可以变化。 它们用于提供简化的界面。 在将类称为“Facade”之前,您应该问自己,它是否提供了简 ...