文档章节

外观模式

loda0128
 loda0128
发布于 2015/05/03 15:49
字数 2035
阅读 48
收藏 0

前一段时间看how tomcat works这本书,发现里面介绍到了Facade(外观、门面)设计模式的使用,在里面,tomcat中通过利用了RequestFacade接口对Request对象的访问进行了安全性控制。我处于好奇,去查了查head first设计模式和GOF设计模式对于这个外观模式的介绍,然后又看了看代理模式,个人感觉,tomcat使用的更像是代理模式,而并非传统意义上的外观模式。

原因如下:

1.GOF中定义外观模式:为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接
口使得这一子系统更加容易使用。ps:这说明外观模式通常是提供一个很简单的接口,调用一系列底层的复杂接口,用来简化客户端的调用,让系统结构对于客户端更加透明。

2.GOF中定义代理模式:为其他对象提供一种代理以控制对这个对象的访问。ps:就像tomcat中顾虑的一样,我不能让客户直接就能拿到Request对象,这样,他会搞的乱七八糟,于是我提供了一个接口,用来代理这个对象,控制它哪些可以被访问,哪些不行。

不过,也有可能我自己理解不到位,其实tomcat用的是外观而我没看出来罢了,。不过先不纠结这些了,我通过对head first设计模式的阅读,以及对gof设计模式的查阅。总结了一下外观模式真正合适的使用场景,希望大家如果有不同意见也能多多给出来,我这边也能学习到。

设想你平时在购物的时候,必然都会有个下单操作,这个操作其实就是对你已经生成的订单进行后续处理,处理的流程比较复杂,因为会涉及到很多流程。这里我就比作有修改订单状态的流程、通知物流中心发货的流程、计费流程、处理结果通知客户的流程。如果把这一系列流程都提供给客户,让客户自行调用的话,客户要自行组织先后关系,会很麻烦,而且也暴露的自己的业务逻辑实现细节,不太安全。这时,我们传说中的外观模式就派上用场了。。。。

来,回顾一下他的定义:为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接
口使得这一子系统更加容易使用

这里,我们的子系统就是修改订单状态的流程、通知物流中心发货的流程、计费流程、处理结果通知客户的流程等一系列流程。我们如果要客户使用起来方便,就要提供一个高层接口,而这个高层接口,我们就简单的定义为下单接口。

package facade;

/**
 * 
* @ClassName: Client 
* @Description: 客户访问的接口 
* 
* 注明:这里的接口是广义的,并不专指传统意义上java的interface
* 我这里指代的是整个提供了某个或者某些功能的Method、class、interface
* 
* @author minjun
*
 */
public class Client {
	
	/**订单接口,通常都是单例实现*/
	private static final OrderService orderService=new OrderService();
	
	public static void main(String[] args) {
		//获取订单编号
		int orderId=getOrderIdFromRequest();
		//执行下单操作
		String msg=orderService.order(orderId);
		//在jsp页面展现下单结果
		showInJsp(msg);
	}

	private static void showInJsp(String msg) {
		System.out.println(msg);
	}

	private static int getOrderIdFromRequest() {
		System.out.println("从客户端发送过来的订单编号为"+7);
		return 7;
	}
}



如上述代码,如果客户能够简单的通过这个orderService的order(下单接口)执行操作,那么会是多么方便啊。这就是我们的目的,提供一个简单的下单接口,具体里面怎么实现的,我们下面再来看(根据TDD测试驱动开发的指导原则)。

package facade;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 
* @ClassName: OrderService 
* @Description: 订单接口 
* @author minjun
* @date 2015年5月3日 下午2:49:16 
*
 */
public class OrderService {
	
	/**单线程的线程池*/
	private static final ExecutorService exec=Executors.newSingleThreadExecutor();
	
	/**账户服务*/
	private static final AccountService accountService=new AccountService();
	
	/**物流服务*/
	private static final LogisticsServcie logisticsService=new LogisticsServcie(); 
	
	/**由于下单操作会涉及到一系列复杂的流程,比如修改订单状态、走支付接口扣费、通知物流系统,所以利用外观模式,提供一个简单的外部接口,让客户访问*/
	public String order(final int orderId) {
		//检查订单的合法性
		checkOrder(orderId);
		
		//异步调用操作,下单操作的一些列子流程通常很耗时,一般是放到队列里面执行,这里图方便,利用一个单线程异步处理
		exec.execute(new Runnable() {
			
			@Override
			public void run() {
				try {
					System.out.println("-----------------order start----------------------");
					//下单的一系列流程都会是一个原子操作,包含在一个事物中,同时成功或者同时失败
					
					//简单模拟开启事物
					Tx.openTransaction();
					//修改订单状态
					updateOrderStatus(orderId);
					
					//通知物流系统
					logisticsService.doNotify(orderId);
					
					//暂时性扣费操作,将客户的钱转移到一个中间平台--例如支付宝,等顾客验收货品的时候真正扣费
					accountService.settle(orderId);
					
					//将处理结果通知用户
					callbackUser(orderId);
					
					//提交事务
					Tx.commit();
					
					System.out.println("-----------------order end----------------------");
					
				} catch (Exception e) {
					Tx.callback();
				}
				
			}
		});
		return "下单成功";
	}

	protected void callbackUser(int orderId) {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("获取用户信息");
		
		System.out.println("提示用户下单流程成功,已经发货并暂时性扣费,以短信的形式发送给客户");
	}

	protected void updateOrderStatus(int orderId) {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("将"+orderId+"订单状态修改为已完成");
	}

	private void checkOrder(int orderId) {
		if(orderId<0){
			throw new RuntimeException("下单失败,订单不合法");
		}
		System.out.println("检查订单完成,合法订单");
	}

}



如上面代码所示,我将复杂的子流程全部扔到了OrderService接口中,通过order方法自行组织这里面的操作顺序。这样,我成功屏蔽了客户对于我流程细节的了解,并且提供了一个用起来更方便的接口让他调用,何乐而不为呢?

下面展示流程的执行结果:

从客户端发送过来的订单编号为7
检查订单完成,合法订单
下单成功
-----------------order start----------------------
开启事物
将7订单状态修改为已完成
通知顺丰处理物流
对用户1的订单7完成扣费操作,合作银行[农业银行]
获取用户信息
提示用户下单流程成功,已经发货并暂时性扣费,以短信的形式发送给客户
提交事务
-----------------order end----------------------



备注:这里我并没有使用类图给大家做演示,是因为虽然大多数人认为类图才是精华,但是我不这么认为,其实定义部分(意图)才是真正的精华,虽然简短,但是很明确。类图反正我是一下子看不出来是什么意思的。

总结:

外观模式

  1. 意图:为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
  2. 动机:将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一是就是引入一个外观Facade)对象,它为子系统中较一般的设施提供了一个单一而简单的界面。
  3. 适用场景:

  • 当你要为一个复杂子系统提供一个简单接口时
  • 客户程序与抽象类的实现部分之间存在着很大的依赖性
  • 当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点。


© 著作权归作者所有

loda0128
粉丝 93
博文 96
码字总数 119400
作品 0
朝阳
程序员
私信 提问
设计模式-外观模式

外观模式是一种使用频率非常高的结构型设计模式, 它通过引入一个外观角色来简化客户端和子系统之间的交互, 为复杂的子系统提供统一的入口, 降低子系统与客户端的耦合度, 且客户端调用非常方便...

hell03W
2016/11/10
37
0
Android的设计模式-外观模式

前言 Android的设计模式系列文章介绍,欢迎关注,持续更新中: Android的设计模式-设计模式的六大原则 一句话总结23种设计模式则 创建型模式: Android的设计模式-单例模式 Android的设计模式...

四月葡萄
2018/01/04
0
0
(十一)外观模式详解(Service第三者插足,让action与dao分手) .

各位好,LZ今天给各位分享一个不太熟悉的面孔,但却是我们最经常使用的设计模式,外观模式。 定义:外观模式是软件工程中常用的一种软件设计模式。它为子系统中的一组接口提供一个统一的高层...

Sheamus
2015/02/06
35
0
一天一种设计模式之十一-----外观模式

一.外观模式简介 外观模式属于结构型模式。 外观模式为子系统中的一组接口提供了一个一致的界面,外观模式定义了一个高层接口,这个接口使得子系统更加容易使用。 当你要为一个复杂的系统提供...

tongqu
2016/03/19
111
1
设计模式----外观模式UML和实现代码(5个必须掌握的设计模式)

一、什么是外观模式? 外观模式(Facade)定义:为子系统中的一组接口提供一个一致的界面,些模式定义了一个高层接口。这个接口使得这一子系统更加容易使用。 类型:结构型模式 顺口溜:适装...

amosli
2015/11/26
94
0

没有更多内容

加载失败,请刷新页面

加载更多

手写RPC框架指北另送贴心注释代码一套

Angular8正式发布了,Java13再过几个月也要发布了,技术迭代这么快,框架的复杂度越来越大,但是原理是基本不变的。所以沉下心看清代码本质很重要,这次给大家带来的是手写RPC框架。 完整代码...

全菜工程师小辉
12分钟前
2
0
【Java】开发收货

简介 谨以此篇,记载开发过程中的一些tips。 编译器 【Shift + F6】可实现变量的联动修改。

Areya
28分钟前
5
0
DOM官方定义

DOM Document Object Model 文档对象模型 DOM的官方定义:W3C的DOM,可以使程序或者脚本(JS或AS\JScript),动态的访问或者操作文档的内容、结构、样式。 DOM只是一个标准,操作网页的标准。...

前端老手
34分钟前
6
0
IT兄弟连 HTML5教程 HTML5的学习线路图 第一阶段学习网页制作

学习HTML5技术可并不是简单学会几个新增的标签而已,HTML5现在可以说是前端所有技术的代名词。需要学习的语言和工具不仅多,对于刚接触他们的新人会感觉很乱。另外,前端开发也会细分很多个开...

老码农的一亩三分地
36分钟前
6
0
可见性有序性,Happens-before来搞定

写在前面 上一篇文章并发 Bug 之源有三,请睁大眼睛看清它们 谈到了可见性/原子性/有序性三个问题,这些问题通常违背我们的直觉和思考模式,也就导致了很多并发 Bug 为了解决 CPU,内存,IO ...

tan日拱一兵
51分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部