作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可。

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

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

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

相信做JAVA的各位大部分是WEB开发,那么肯定都对XXXDao,XXXService非常熟悉了,这显然和外观模式有一腿。当然,还有一大部分是android开发,LZ没接触过android开发,但是LZ大胆的想象,在移动领域的JAVA开发,应该也有类似的情况发生。

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

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

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

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();
} }

以上便是我们的外观接口和实现类,它当中的功能一般是根据是客户端的需要定制的,将客户端的一个完整功能作为一个行为,然后调用子系统完成。下面我们看看客户端的调用。

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在下面还给出了原始的调用方式,可以看出在外观模式的作用下,我们客户端只依赖外观一个接口,而在原始的方式下,我们的客户端依赖于整个子系统,所以外观模式主要解决的是类之间的耦合过于复杂。

附上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没有像之前一样写一堆示例代码给各位看,更多的是在讨论外观模式的应用场景和应用范围,希望各位看完之后对外观模式有一个宏观的认识,而不是仅限于代码层次的理解。

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

下期预告,命令模式。

(十一)外观模式详解(Service第三者插足,让action与dao分手)的更多相关文章

  1. 设计模式之 外观模式详解(Service第三者插足,让action与dao分手)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,LZ今天给各位分享一 ...

  2. 十一:外观模式详解(Service,action与dao)

    定义:外观模式是软件工程中常用的一种软件设计模式.它为子系统中的一组接口提供一个统一的高层接口.这一接口使得子系统更加容易使用. 该定义引自百度百科,它的表现很简单,将一系列子接口的功能进行整理,从而 ...

  3. Docker Kubernetes Service 网络服务代理模式详解

    Docker Kubernetes  Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...

  4. Extjs MVC开发模式详解

    Extjs MVC开发模式详解   在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开发模式, ...

  5. JavaScript严格模式详解

    转载自阮一峰的博客 Javascript 严格模式详解   作者: 阮一峰 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict m ...

  6. HTTP协议头部与Keep-Alive模式详解

    HTTP协议头部与Keep-Alive模式详解 .什么是Keep-Alive模式? 我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器 ...

  7. (" use strict")Javascript 严格模式详解

    Javascript 严格模式详解 转载别人的博客内容,浏览了一遍,没有全部吸收,先保存一下链接 http://www.ruanyifeng.com/blog/2013/01/javascript_s ...

  8. Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...

  9. HTTP协议Keep-Alive模式详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp22 HTTP协议Keep-Alive模式详解 1.什么是Keep-Aliv ...

随机推荐

  1. ELK IIS 日志-->logstash-->ElasticSearch

    NXLOG 配置 #define ROOT C:\Program Files\nxlog define ROOT C:\Program Files (x86)\nxlog Moduledir %ROO ...

  2. 提升效率(时间准确性),减少时间和资源的消耗——由89C52/89C51的定时器中断引出的一些问题

    尽量用最少的文字描述清楚问题. 事情起因是这样的: 要做遥控小车的平台迁移,STM32开发板无法方便地供电,因此又拿出了尘封的51(STC89C52RC),搭配上最小系统板就可以用排针加杜邦线供电了. ...

  3. arc如何破循环或交叉引用

    IOS两种常见的循环引用: 1,两个类之间互相定义对方的引用 如下: //ARC code @interface A : NSObject @property (nonatomic,strong) B ...

  4. [转]TCP协议中的三次握手和四次挥手(图解)

    本文转自:http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来 ...

  5. Android View和ViewGroup

    View和ViewGroup Android的UI界面都是由View和ViewGroup及其派生类组合而成的. 其中,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也 ...

  6. SQL Learning Notes

    Sams Teach Yourself SQL in 10 Minutes

  7. 第一天接触Orchard

    第一天接触Orchard 为什么要研究Orchard 呢? 楼主是因为要研究下最新的ASP.NET技术, Orchard 用的人多,历史也比较久,算是老牌了 再就是中文资料比较多,Orchard 有中 ...

  8. poj1001 Exponentiation 大数的幂

    Description Problems involving the computation of exact values of very large magnitude and precision ...

  9. Stunnel使用

     建立加密隧道 使用 Stunnel 建立加密隧道 附件中的 Server 和 Clinet 都是已经配置好了的,只需修改 Server 的 stunnel.conf 的 connect 为实际的ip ...

  10. [No000032]程序员的年龄天花板

    程序员职业生涯中流行这这样一个定律:35岁定律,那35岁以上的老程序员都干吗去了呢?为了讨论程序员的职业寿命,我们先得给公司或者团队分分类.大概有这么三类: 外包型 项目型 产品型 咱们一一来说一下吧 ...