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

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

相信做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的示例,各位的项目中到处都充斥着这种例子。

十一:外观模式详解(Service,action与dao)的更多相关文章

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

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

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

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

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

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

  4. Extjs MVC开发模式详解

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

  5. ext.js的mvc开发模式详解

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

  6. JavaScript严格模式详解

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

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

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

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

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

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

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

随机推荐

  1. 邮Z速递物流,让用户密码在网络中遨游

    " 最近分析快递行业的APP上瘾了,求解救." 邮政作为快递行业一个傻大黑的存在,一直很奇怪,我一直在纳闷,邮政和EMS到底是不是一家,在很多网点,它们是一体的存在,但很多东西,又 ...

  2. Wireshark小技巧:将IP显示为域名

    "  本文介绍如何使Wireshark报文窗口的Source栏及Destination内的IP直接显示为域名,提升报文分析效率." 之前内容发现部分不够严谨的地方,所以删除重发. ...

  3. [转] Hystrix 使用与分析

    原文地址:http://hot66hot.iteye.com/blog/2155036 转载请注明出处哈:http://hot66hot.iteye.com/blog/2155036 一:为什么需要H ...

  4. Could not resolve resource location pattern [classpath:com/****/mappers/*.xml]: class path resource [com/****/mappers/] cannot be resolved to URL because it does not exist的问题

    这里建议先去看看路径的问题,看看application.xml的里面的导入的相应的配置文件的路径有没有问题,如下: 再者看看相应的注解有没有加上,service和controller等的注解 如果再不 ...

  5. pdfium 例子

    #include <stdio.h> #include <fpdfview.h> int main(int argc, char** argv) { FPDF_InitLibr ...

  6. php 学习笔记之日期时间操作一箩筐

    格式化日期时间 date : 格式化日期时间 场景 将当前日期时间或者特定日期时间格式化输出为特定格式的字符串,常用于人性化展示信息. 说明 返回给定时间戳格式化后所产生的日期时间字符串,如果没有给出 ...

  7. ORB-SLAM2 地图加载

    一.前面说了ORB-SLAM地图的保存部分,继续说地图如何加载,因为加载部分相比保存要稍微复杂一些,所以要多说一点. 二.ORB-SLAM2地图加载构成 首先同样是在头文件中声明加载函数,包含地图点和 ...

  8. JS中的undefined,null,"",0,'0'和false

    ){ console.log(); } '){ console.log() } '){ console.log() } if(false==0.0){ console.log() } if(false ...

  9. 第04组 Alpha冲刺(5/6)

    队名:new game 组长博客:戳 作业博客:戳 组员情况 鲍子涵(队长) 燃尽图 过去两天完成了哪些任务 才两天,也就是实现一些功能而已 复习了一下SuffixAutomata 接下来的计划 实现 ...

  10. [NewLife.XCode]导入导出(实体对象百变魔君)

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示例代码和 ...