(十一)外观模式详解(Service第三者插足,让action与dao分手) .

  各位好,LZ今天给各位分享一个不太熟悉的面孔,但倒是咱们最常用的设计模式,外观模式。java

  定义:外观模式是软件工程中经常使用的一种软件设计模式。它为子系统中的一组接口提供一个统一的高层接口。这一接口使得子系统更加容易使用。android

   该定义引自百度百科,它的表现很简单,将一系列子接口的功能进行整理,从而产生一个更高层的接口。web

   相信作JAVA的各位大部分是WEB开发,那么确定都对XXXDao,XXXService很是熟悉了,这显然和外观模式有一腿。固然,还有一大部分是android开发,LZ没接触过android开发,可是LZ大胆的想象,在移动领域的JAVA开发,应该也有相似的状况发生。编程

   接下来,咱们来看看外观模式的标准类图。设计模式


    上述即是外观模式的类图,它主要由两部分组成,一部分是子系统(包括接口,实现类,等等),一部分是外观接口和实现类,外观接口负责提供客户端定制的服务,外观实现则负责组合子系统中的各个类和接口完成这些服务,外观接口则是提供给客户端使用的,这样就解除了客户端与子系统的依赖,而让客户端只依赖于外观接口,这是一个优秀的解耦实践。架构

    下面LZ依然使用JAVA代码将上述的类图诠释出来,咱们来直观的看看外观模式的实现方式。首先是咱们的子系统,它包括三个接口,三个实现,LZ这里一并给出。eclipse

package com.facade;  
  
public interface Sub1 {  
  
    void function1();  
      
}
package com.facade;  
  
public interface Sub2 {  
  
    void function2();  
      
}
package com.facade;  
  
public interface Sub3 {  
  
    void function3();  
      
}
package com.facade;  
  
public class Sub1Impl implements Sub1{  
  
    public void function1() {  
        System.out.println("子系统中Sub1接口的功能");  
    }  
  
}
package com.facade;  
  
public class Sub2Impl implements Sub2{  
  
    public void function2() {  
        System.out.println("子系统中Sub2接口的功能");  
    }  
  
}
package com.facade;  
  
public class Sub3Impl implements Sub3{  
  
    public void function3() {  
        System.out.println("子系统中Sub3接口的功能");  
    }  
  
}

   以上即是咱们模拟出的一个子系统,那么如今即是咱们最重要的接口出场的时候了,LZ给出Facade以及它的简单实现。工具

package com.facade;  
  
public interface Facade {  
      
    /*  下面随便组装几个功能  */  
      
    void function12();  
      
    void function23();  
      
    void function123();  
      
}
package com.facade;  
  
public class FacadeImpl implements Facade{  
  
    private Sub1 sub1;  
      
    private Sub2 sub2;  
      
    private Sub3 sub3;  
      
    public FacadeImpl() {  
        super();  
        this.sub1 = new Sub1Impl();  
        this.sub2 = new Sub2Impl();  
        this.sub3 = new Sub3Impl();  
    }  
  
    public FacadeImpl(Sub1 sub1, Sub2 sub2, Sub3 sub3) {  
        super();  
        this.sub1 = sub1;  
        this.sub2 = sub2;  
        this.sub3 = sub3;  
    }  
  
    public void function12() {  
        sub1.function1();  
        sub2.function2();  
    }  
  
    public void function23() {  
        sub2.function2();  
        sub3.function3();  
    }  
  
    public void function123() {  
        sub1.function1();  
        sub2.function2();  
        sub3.function3();  
    }  
  
}

   以上即是咱们的外观接口和实现类,它当中的功能通常是根据是客户端的须要定制的,将客户端的一个完整功能做为一个行为,而后调用子系统完成。下面咱们看看客户端的调用。this

package com.facade;  
  
public class Client {  
  
    public static void main(String[] args) {  
        Facade facade = new FacadeImpl();  
        facade.function12();  
        System.out.println("-------------------------");  
        facade.function23();  
        System.out.println("-------------------------");  
        facade.function123();  
          
        /*  以上为使用了外观模式的调用方式,如下为原始方式   */  
          
        System.out.println("-------------如下原始方式--------------");  
        Sub1 sub1 = new Sub1Impl();  
        Sub2 sub2 = new Sub2Impl();  
        Sub3 sub3 = new Sub3Impl();  
        sub1.function1();  
        sub2.function2();  
        System.out.println("-------------------------");  
        sub2.function2();  
        sub3.function3();  
        System.out.println("-------------------------");  
        sub1.function1();  
        sub2.function2();  
        sub3.function3();  
    }  
      
}

   LZ在下面还给出了原始的调用方式,能够看出在外观模式的做用下,咱们客户端只依赖外观一个接口,而在原始的方式下,咱们的客户端依赖于整个子系统,因此外观模式主要解决的是类之间的耦合过于复杂。spa

   附上LZ运行结果。

   以上即是标准的外观模式展示,LZ下面再给出须要知晓的几点。

    1,实际使用当中,接口并非必须的,虽然说根据依赖倒置原则,不管是处于高层的外观层,仍是处于底层的子系统,都应该依赖于抽象,可是这会倒置子系统的每个实现都要对应一个接口,从而致使系统的复杂性增长,因此这样作并非必须的。

    2,外观接口当中并不必定是子系统中某几个功能的组合,也能够是将子系统中某一个接口的某一功能单独暴露给客户端。

    3,外观接口若是须要暴露给客户端不少的功能的话,能够将外观接口拆分为若干个外观接口,如此便会造成一层外观层。

    上述LZ给出的第三点,即是为了引出咱们标题当中的service,相信各位作过web开发的都见过咱们项目中不少的service和dao(注:小型项目或许不须要service这一层),这一层service层,有一个很是重要的做用,就是为了方便咱们管理项目中与业务逻辑相关的事物,而service层,实际上是给咱们的事务管理器提供了一个能够方便的配置切入点的事物管理层。

    除了上述这个重要的功能外,service层同时也是组合dao层暴露给action的功能,dao层的各个类只是简单的数据操做对象,它们不具备业务逻辑,而赋予了它们业务逻辑方便action调用的功臣,正是service这一层。各位能够想象一下,假设没有service这一层,你的action当中有不少功能须要依赖多少个dao才能够完成工做。

    同时在WEB项目中,有的项目会抽象出一层service接口和一层dao接口,这是为了下降客户端(这里的客户端能够认为是action)与业务实现细节以及service外观层与数据操做实现细节的耦合,而有的项目则没有抽象层,这也并不是就是不合适的。

   首先添加抽象层会大大的加重项目的类文件数量,从而使项目的复杂性增长,并且在项目刚进入开发的时候,每每接口是不稳定的,由于咱们常常会须要要给某一个service添加一个方法,而为了将方法暴露给客户端(即action),咱们必须将该方法添加到对应的接口当中。

   因此针对这一状况,咱们更好的作法是等到接口行为相对稳定时,再考虑是否要重构去添加抽象的接口,并且如今的IDE工具都在必定程度上对重构进行了支持,好比eclipse就能够直接导出一个类的接口,因此咱们彻底能够在须要时快速的给项目添加抽象的接口层。

   相比起观察者模式,适配器模式等适合小规模使用的设计模式,外观模式更多的是大范围的使用,它会是不少时候支撑咱们整个架构的设计思路。

    鉴于此,LZ此处再也不给出具体的service和dao的示例,各位的项目中处处都充斥着这种例子。

     若是形象的去形容外观模式在WEB中的应用,能够说它让action和dao分了手,而插入了一个第三者service,断开了action与dao的耦合,转而使用更高层的service。

    这里须要提醒各位的是,外观模式并非简单的使用组合将功能组合起来,也就是说它的重点不在组合功能,而在于制做一个对外暴露的外观。它通常是用来将一个子系统(注意,是一个子系统,也就是说外观并非简单的几个类的组合就是外观模式了)的功能进行调配,暴露给客户端一个外部的表象,使得客户端与子系统断开依赖关系。

    因为外观模式属于一种“大”模式,因此咱们平时不多会接触到,可是有不少技术的应用,其实都有着外观模式的影子。

     好比webservice,它是给一个WEB应用提供一个外观,让客户端能够调用一些接口去使用WEB应用当中的一些功能或者说服务。再好比API,中文名称应用程序接口,它其实也能够看作是给底层的操做系统作了一层外观,使程序猿在编程的时候能够直接使用外观提供的接口,从而间接的指挥操做系统完成一些事情。

    本次外观模式的分享,LZ没有像以前同样写一堆示例代码给各位看,更多的是在讨论外观模式的应用场景和应用范围,但愿各位看完以后对外观模式有一个宏观的认识,而不是仅限于代码层次的理解。

    好了,本次外观模式的分享就到此结束了,谢谢各位的收看,下期再见。

                    下期预告,命令模式。

相关文章
相关标签/搜索