设计模式之 外观模式详解(Service第三者插足,让action与dao分手)
作者: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分手)的更多相关文章
- (十一)外观模式详解(Service第三者插足,让action与dao分手)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,LZ今天给各位分享一 ...
- 十一:外观模式详解(Service,action与dao)
定义:外观模式是软件工程中常用的一种软件设计模式.它为子系统中的一组接口提供一个统一的高层接口.这一接口使得子系统更加容易使用. 该定义引自百度百科,它的表现很简单,将一系列子接口的功能进行整理,从而 ...
- 设计模式之迭代器模式详解(foreach的精髓)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,很久没以LZ的身份和 ...
- 设计模式之 原型模式详解(clone方法源码的简单剖析)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...
- 设计模式——模版方法模式详解(论沉迷LOL对学生的危害)
. 实例介绍 在本例中,我们使用一个常见的场景,我们每个人都上了很多年学,中学大学硕士,有的人天生就是个天才,中学毕业就会微积分,因此得了诺贝尔数学奖:也有的人在大学里学了很多东西,过得很充实很满意 ...
- Java设计模式之状态模式详解
(本文由言念小文原创,转载请注明出处) 在实际工作中经常遇到某个对象,处于不同的状态有不同行为逻辑.且状态之间可以相互迁移的业务场景,特别是在开发通信协议栈类软件中尤为多见.<设计模式之禅> ...
- JAVA 设计模式之 工厂模式详解
一.简单工厂模式 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类 的实例.属于创建型模式,但它不属于 GOF,23 种设计模式 (参考资料: ht ...
- javascript设计模式之解释器模式详解
http://www.jb51.net/article/50680.htm 神马是“解释器模式”? 先翻开<GOF>看看Definition:给定一个语言,定义它的文法的一种表示,并定义一 ...
- 面向对象设计模式_生成器模式详解(Builder Pattern)
首先提出一个很容易想到应用场景: 手机的生产过程:手机有非常多的子件(部件),成千上万,不同品牌的手机的生产过程都是复杂而有所区别的,相同品牌的手机在设计上也因客户需求多样化,大到型号,小到颜色,是否 ...
随机推荐
- HI3531由DMA 发起PCIe 事务
Hi3531 PCIe 控制器内含DMA 控制器,DMA 控制器包含有两个DMA 通道(一个 DMA 读通道和一个DMA 写通道).PCIe 控制器内包含的DMA 控制器用于大数据量 的存储器读写事务 ...
- MiniGUI + Hi3531 笔记 .
一.移动光驱安装Ubuntu 10.04 1. 重启系统按住Delete进入BIOS界面! 2. 退出/高级模式 --> 启动 --> 启动设备选择. 移动光驱正常被识别后这里应该 ...
- java.sql.SQLException: Access denied for user 'sa'@'localhost' (using password: NO)
1.错误描述 INFO:2015-05-01 16:53:29[main] - HHH000228: Running hbm2ddl schema update INFO:2015-05-01 16: ...
- SQL面试题收录
1.用一条SQL语句 查询出每门课都大于80分的学生姓名 SELECT DISTINCT NAME FROM t_score_tab WHERE NAME NOT IN (SELECT DISTINC ...
- ubuntu14.04 编译安装highpoint rocketraid 2720驱动
highpoint官方只有ubuntu12.10驱动,对于ubuntu14.04或者12.04,需要手工编译安装驱动. 基本步骤: 1.下载rocketraid 2720驱动源代码 2.在一台装有ub ...
- EF Core下利用Mysql进行数据存储在并发访问下的数据同步问题
小故事 在开始讲这篇文章之前,我们来说一个小故事,纯素虚构(真实的存钱逻辑并非如此) 小刘发工资后,赶忙拿着现金去银行,准备把钱存起来,而与此同时,小刘的老婆刘嫂知道小刘的品性,知道他发工资的日子,也 ...
- 异常-----The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path。
1, 找到新建页面所在的工程名字,然后左键选中,右键弹出功能菜单,选择Build Path,进入配置路径. 2, 在java build path 页面的下选择Libraries栏目(默认选择),点击 ...
- [Luogu2852][USACO06DEC]牛奶模式Milk Patterns
Luogu 一句话题意 给出一个串,求至少出现了\(K\)次的子串的最长长度. sol 对这个串求后缀数组. 二分最长长度. 如果有\(K\)个不同后缀他们两两的\(lcp\)都\(>=mid\ ...
- Bzoj2134:单选错位
题面 Bzoj Sol 第\(i\)道题选对的概率就是\(\frac{min(a[i-1], a[i])}{a[i]*a[i-1]}\) # include <bits/stdc++.h> ...
- webpack深入场景——开发环境和生产环境配置
以前自己写一小项目时,webpack的配置基本就是一套配置,没有考虑生产环境和开发环境的区分,最近在做一个复杂的商城项目接触到了webpack的高级配置,经过两天的研究,写出了一份目前来说比叫满意的配 ...