设计模式之外观模式
外观模式(门面模式)
定义:它为子系统中的一组接口提供一个统一的高层接口。这一接口使得子系统更加容易使用
类型:结构型
适用场景:
- 子系统越来越复杂,增加外观模式提供简单的接口调用
- 构建多层系统接口,利用外观对象作为每层的入口,简化层间调用
优点:
- 简化了调用过程,无需深入了解子系统,防止带来的风险
- 减少系统依赖,松散耦合
- 更好的划分访问层次
- 符合迪米特法则(最少知道原则)
缺点:
- 增加子系统,扩展子系统行为容易引入风险
- 不符合开闭原则
UML类图:
Facade:门面角色,客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。一般情况下,本橘色会将所有从客户端发来的请求委托到相应的子系统,也就是说该角色并没有实际的业务逻辑,而是一个委托类
Subsystem:子系统角色,可以同时有一个或者多个子系统。每一个子系统都不是单独的类,而是一个类的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户端而已
示例
ModuleA,ModuleB,ModuleC均是独立的功能模块,现在把他们都看作是子系统的内部结构组成,提供个Facade门面供客户端调用
- 模块A、模块B、模块C
public class ModuleA {
//示意方法
public void testA() {
System.out.println("调用ModuleA中的testA方法");
}
}
public class ModuleB {
//示意方法
public void testB() {
System.out.println("调用ModuleB中的testB方法");
}
}
public class ModuleC {
//示意方法
public void testC() {
System.out.println("调用ModuleC中的testC方法");
}
}
- Facade门面(对子系统的各个功能模块进行封装、子系统的功能模块之间的调用逻辑也可以在这里完成)
public class Facade {
//示意方法,满足客户端需要的功能
public void test(){
ModuleA a = new ModuleA();
a.testA();
ModuleB b = new ModuleB();
b.testB();
ModuleC c = new ModuleC();
c.testC();
}
}
- 客户端
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.test();
}
}
Facade类其实相当于A、B、C模块的外观界面,有了这个Facade类,那么客户端就不需要亲自调用子系统中的A、B、C模块了,也不需要知道系统内部的实现细节,甚至都不需要知道A、B、C模块的存在,客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易地使用系统。
- 在日常J2EE开发中,我们最常与controller/service/dao打交道,这就是典型的外观模式的实现,这里以一个订单业务举例
图中的Dao层的OrderDao、OrderLogDao可以看做是子系统的组成部分,主要围绕的是数据库的增删改查,而Service层中的OrderServiceImpl就是我们外观对象实现,通常我们会根据具体的业务逻辑去调用dao层提供的api,这里就提供了一个createOrder
创建订单的外观方法给Contorller层(客户端)进行调用,客户端根本不需要了解具体订单生成逻辑就可以完成订单的创建。这里对外观类进行了接口抽象,客户端依赖的是OrderService接口而不是OrderServiceImpl实现类,这样就解除了客户端与子系统的依赖,而让客户端只依赖于外观接口,这是一个优秀的解耦实践。
相关的设计模式
-
外观模式和中介者模式
外观模式关注的是外界和子系统之间的交互,而中介者模式关注的是子系统之间的内部交互
-
外观模式和单例模式
通常可以把外观模式中的外观对象做成是单例模式
-
外观模式和抽象工厂模式
外观类可以通过抽象工厂获取子系统的实例,这样子系统可以对外观类进行屏蔽
-
外观模式和代理模式
代理对象代表一个单一对象而外观对象代表一个子系统,代理的客户对象无法直接访问对象,由代理提供单独的目标对象的访问,而通常外观对象提供对子系统各元件功能的简化的共同层次的调用接口。代理是一种原来对象的代表,其他需要与这个对象打交道的操作都是和这个代表交涉的
-
外观模式和适配器模式
外观与适配器都是对现存系统的封装。外观定义的新的接口,而适配器则是复用一个原有的接口,适配器是使两个已有的接口协同工作,而外观则是为现存系统提供一个更为方便的访问接口。如果硬要说外观是适配,那么适配器有用来适配对象的,而外观是用来适配整个子系统的。也就是说,外观所针对的对象的粒度更大
使用典范
- SLF4J日志框架
- tomcat中的RequestFacade
- java.lang.Class
参考
原文地址:https://www.cnblogs.com/DiDi516/p/12733103.html
- 10步骤优化SQL Server 数据库性能
- 漫谈语音合成之Char2Wav模型
- [基础]Javascript中的继承示例代码
- javascript天生就具备类似c#中的"委托"功能
- 使用MonoDevelop开发跨平台的应用程序
- Pycharm使用技巧总结
- [基础]电话/手机常见验证的Javascript示例
- 按照Web Service方式调用WCF服务的问题
- 利用Lucene打造站内搜索引擎的思路
- Lucene.Net 删除索引DeleteDocuments的注意事项
- 使用VS2010的Database 项目模板统一管理数据库对象
- 利用c#制作托盘程序,并禁止多个应用实例运行
- dotNET跨平台相关文档整理
- .NET Core 2.0 正式发布信息汇总
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- uniapp常用提示框uni.showToast(OBJECT)
- MySQL 索引(3)
- TS 设计模式04 - 适配器模式
- WebRTC | 原理、架构、框架目录、运行机制、核心类、PeerConnection调用过程等详解
- sql注入总结笔记
- WebRTC | Web服务器原理、Nodejs工作原理、Nodejs事件处理流程、V8引擎等要点解析
- OpenGL ES 3.0 | 围绕HelloTriangle实战案例 展开 渲染流程分析
- 基于 Kotlin + Netty 实现一个简单的 TCP 自定义协议
- dnslog带出——sqli-labs第8关
- Boolean源码解剖学
- SpringBoot+Mybatis整合出现org.apache.ibatis.binding.BindingException: Invalid bound statement (not found
- xss-labs第1~13关
- 在虚拟机上搭建xss平台
- 一个速度快,内存占用小的一致性哈希算法
- 一文搞定web微信第三方登录