JAVA设计模式之门面模式(外观模式)

医院的例子

  现代的软件系统都是比较复杂的,设计师处理复杂系统的一个常见方法便是将其“分而治之”,把一个系统划分为几个较小的子系统。如果把医院作为一个子系统,按照部门职能,这个系统可以划分为挂号、门诊、划价、化验、收费、取药等。看病的病人要与这些部门打交道,就如同一个子系统的客户端与一个子系统的各个类打交道一样,不是一件容易的事情。

  首先病人必须先挂号,然后门诊。如果医生要求化验,病人必须首先划价,然后缴费,才可以到化验部门做化验。化验后再回到门诊室。

上图描述的是病人在医院里的体验,图中的方框代表医院。

  解决这种不便的方法便是引进门面模式,医院可以设置一个接待员的位置,由接待员负责代为挂号、划价、缴费、取药等。这个接待员就是门面模式的体现,病人只接触接待员,由接待员与各个部门打交道。

门面模式的结构

  门面模式没有一个一般化的类图描述,最好的描述方法实际上就是以一个例子说明。

 由于门面模式的结构图过于抽象,因此把它稍稍具体点。假设子系统内有三个模块,分别是ModuleA、ModuleB和ModuleC,它们分别有一个示例方法,那么此时示例的整体结构图如下:

在这个对象图中,出现了两个角色:

  ●  门面(Facade)角色 :客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。

  ●  子系统(SubSystem)角色 :可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,而是一个类的集合(如上面的子系统就是由ModuleA、ModuleB、ModuleC三个类组合而成)。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。

源代码

  子系统角色中的类:

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class ModuleA {  
  2.     //示意方法  
  3.     public void testA(){  
  4.         System.out.println("调用ModuleA中的testA方法");  
  5.     }  
  6. }  
[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class ModuleB {  
  2.     //示意方法  
  3.     public void testB(){  
  4.         System.out.println("调用ModuleB中的testB方法");  
  5.     }  
  6. }  


 

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class ModuleC {  
  2.     //示意方法  
  3.     public void testC(){  
  4.         System.out.println("调用ModuleC中的testC方法");  
  5.     }  
  6. }  


 门面角色类:

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class Facade {  
  2.     //示意方法,满足客户端需要的功能  
  3.     public void test(){  
  4.         ModuleA a = new ModuleA();  
  5.         a.testA();  
  6.         ModuleB b = new ModuleB();  
  7.         b.testB();  
  8.         ModuleC c = new ModuleC();  
  9.         c.testC();  
  10.     }  
  11. }  

客户端角色类:

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class Client {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         Facade facade = new Facade();  
  6.         facade.test();  
  7.     }  
  8.   
  9. }  

 Facade类其实相当于A、B、C模块的外观界面,有了这个Facade类,那么客户端就不需要亲自调用子系统中的A、B、C模块了,也不需要知道系统内部的实现细节,甚至都不需要知道A、B、C模块的存在,客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易地使用系统。

 


 

门面模式的实现

  使用门面模式还有一个附带的好处,就是能够有选择性地暴露方法。一个模块中定义的方法可以分成两部分,一部分是给子系统外部使用的,一部分是子系统内部模块之间相互调用时使用的。有了Facade类,那么用于子系统内部模块之间相互调用的方法就不用暴露给子系统外部了。

  比如,定义如下A、B、C模块。

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class Module {  
  2.     /** 
  3.      * 提供给子系统外部使用的方法 
  4.      */  
  5.     public void a1(){};  
  6.       
  7.     /** 
  8.      * 子系统内部模块之间相互调用时使用的方法 
  9.      */  
  10.     private void a2(){};  
  11.     private void a3(){};  
  12. }  


 

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class ModuleB {  
  2.     /** 
  3.      * 提供给子系统外部使用的方法 
  4.      */  
  5.     public void b1(){};  
  6.       
  7.     /** 
  8.      * 子系统内部模块之间相互调用时使用的方法 
  9.      */  
  10.     private void b2(){};  
  11.     private void b3(){};  
  12. }  


 

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class ModuleC {  
  2.     /** 
  3.      * 提供给子系统外部使用的方法 
  4.      */  
  5.     public void c1(){};  
  6.       
  7.     /** 
  8.      * 子系统内部模块之间相互调用时使用的方法 
  9.      */  
  10.     private void c2(){};  
  11.     private void c3(){};  
  12. }  


 

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class ModuleFacade {  
  2.       
  3.     ModuleA a = new ModuleA();  
  4.     ModuleB b = new ModuleB();  
  5.     ModuleC c = new ModuleC();  
  6.     /** 
  7.      * 下面这些是A、B、C模块对子系统外部提供的方法 
  8.      */  
  9.     public void a1(){  
  10.         a.a1();  
  11.     }  
  12.     public void b1(){  
  13.         b.b1();  
  14.     }  
  15.     public void c1(){  
  16.         c.c1();  
  17.     }  
  18. }  

这样定义一个ModuleFacade类可以有效地屏蔽内部的细节,免得客户端去调用Module类时,发现一些不需要它知道的方法。比如a2()和a3()方法就不需要让客户端知道,否则既暴露了内部的细节,又让客户端迷惑。对客户端来说,他可能还要去思考a2()、a3()方法用来干什么呢?其实a2()和a3()方法是内部模块之间交互的,原本就不是对子系统外部的,所以干脆就不要让客户端知道。

一个系统可以有几个门面类

  在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。当然这并不意味着在整个系统里只有一个门面类,而仅仅是说对每一个子系统只有一个门面类。或者说,如果一个系统有好几个子系统的话,每一个子系统都有一个门面类,整个系统可以有数个门面类。

为子系统增加新行为

  初学者往往以为通过继承一个门面类便可在子系统中加入新的行为,这是错误的。门面模式的用意是为子系统提供一个集中化和简化的沟通管道,而不能向子系统加入新的行为。比如医院中的接待员并不是医护人员,接待员并不能为病人提供医疗服务。

 

门面模式的优点

  门面模式的优点:

  ●  松散耦合

  门面模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。

  ●  简单易用

  门面模式让子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟门面类交互就可以了。

  ●  更好的划分访问层次

  通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。


 

作者:jason0539

微博:http://weibo.com/2553717707

博客:http://blog.csdn.net/jason0539(转载请说明出处)

17

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

里程碑 .Net7再更新,从此彻底碾压Java!

.NET 7 Preview1发布了,没时间实操?先快来看看.NET7的七项重大改进!1、不再支持.NET 7应用程序、运行时和SDK的多级查找(MLL)2、PATH停止向.NET 7运行时和SDK添加32位.NET3、默认情况下, dotnet build/publ…

软件架构知识体系

2019独角兽企业重金招聘Python工程师标准>>> 由于[GOF95]是论述软件模式的著作的第一本,也是OO设计理论著作中最流行的一本,因此有些人常常使用设计模式(Design Pattern)一词来指所有直接处理软件的架构、设计、程序实…

C语言之最好理解的通过函数指针作为参数实现回调函数

1、函数指针回调解释 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数 2、代码实现 #include <stdio.h>int sub(int a, int b);int sub1(int a, int b, in…

asp.net 的page 基类页面 做一些判断 可以定义一个基类页面 继承Page类 然后重写OnPreLoad事件...

public class BasePage:Page protected override void OnPreLoad(EventArgs e){ base.OnPreLoad(e); .................. } 这样 就可以在基类页面 统一做一些判断了 转载于:https://www.cnblogs.com/maijin/p/4681871.html

C#不要再使用Npoi啦,使用MiniExcel操作Excel文件更快更高效!

1.简介MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。目前主流框架如Npoi 需要将数据全载入到内存方便操作&#xff0c;但这会导致内存消耗问题。MiniExcel 尝试以 Stream 角度写底层算法逻辑&#xff0c;能让原本1000多MB占用降低到几MB&#xff0c;避免内…

#、%和$符号在OGNL表达式中的作用

#、%和$符号在OGNL表达式中经常出现&#xff0c;而这三种符号也是开发者不容易掌握和理解的部分。在这里笔者简单介绍它们的相应用途。1&#xff0e;#符号的用途一般有三种。 1)访问非根对象属性&#xff0c;例如示例中的#session.msg表达式&#xff0c;由于Struts 2中值栈被…

Android之获取证书文件(pfx格式)的公钥和私钥

1、把pfx证书文件放入sdcard adb push ***.pfx /sdcard/ 2、解析获取公钥和私钥 //证书解析 String path = Environment.getExternalStorageDirectory().getPath() + "/sim_shield.pfx";public static Map<String, byte[]> parsePfx(String pfxPath, String…

go和python切片的不同

2019独角兽企业重金招聘Python工程师标准>>> go有切片slice类型&#xff0c;python有列表和元组&#xff0c;这两种语言都有切片操作。 但是它们的切片操作是完全不同的。 首先说第一个&#xff0c;go的切片&#xff0c;其成员是相同类型的&#xff0c;python的列…

编程算法 - 切割排序 代码(C)

切割排序 代码(C)本文地址: http://blog.csdn.net/caroline_wendy排序切割, 把一个数组分为, 大于k\小于k\等于k的三个部分.能够使用高速排序的Partition函数, 进行处理, 把大于k的放在左边, 小于k的放在右边.使用一个变量记录中间的位置, 则时间复杂度为O(3n/2).代码:/** main…

【C#/.NET】.NET6中全局异常处理

微信公众号&#xff1a;趣编程ACE关注可了解每日一更的.NET日常实战开发技巧&#xff0c;欢迎公众号留言开发 获取源码;.NET6中全局异常处理异常处理是我们在程序开发中不可或缺的一环&#xff0c;下文我将会结合程序Sample讲解如何在.NET6中有效处理异常。Try-Ctach 块包裹自定…

JAVA学习笔记--初识容器类库

一、前言 JAVA中一切皆为对象&#xff0c;因而&#xff0c;持有对象显得尤为重要。 在JAVA中&#xff0c;我们可以通过创建一个对象的引用的方式来持有对象&#xff1a; HoldingObject holding; 也可以创建一个对象数组来持有一组特定类型的对象&#xff1a; HoldingObject hol…

如何保证执行异步方法时不会遗漏 await 关键字

前言在.NET Core 中已经广泛使用异步编程&#xff0c;代码中充斥着大量的 async 和 await 关键字。但有时候&#xff0c;调用一个异步方法时可能会忘了写 await。这会造成什么问题呢&#xff1f;问题重现示例代码如下&#xff1a;[HttpGet] public async Task<IEnumerable&l…

Andorid之打包出现Proguard returned with erro code 1.See console解决办法

1、错误 我们进行签名操作的时候&#xff0c;提示下面错误 Proguard returned with erro code 1.See console 然后在console里面提示这个 you should check if you need to specify additional program jars 2、原因 找不到引用包导致 2、解决办法 我们可以在proguard-projec…

CCF-CSP认证201312-1(出现次数最多的数)

CCF-CSP认证201312-1&#xff08;出现次数最多的数&#xff09; 问题描述   给定n个正整数&#xff0c;找出它们中出现次数最多的数。如果这样的数有多个&#xff0c;请输出其中最小的一个。 输入格式   输入的第一行只有一个正整数n(1 ≤ n ≤ 1000)&#xff0c;表示数字…

Java的原始数据类型一共就8个

Java的原始数据类型一共就8个&#xff0c;分别是&#xff1a;byte、short、int、long、boolean、char、float、double。注意这些是大小写敏感的&#xff0c;而Boolean是boolean的封装类(wrapper class)。 在java中一个类只能有一个直接父类&#xff0c;但是可以实现多个接口&a…

Avalonia跨平台入门第十二篇之动画效果

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底、控件的锁定、自定义Window样式;今天趁着空闲时间接着去摸索简单的动画效果,毕竟有点动画的东西还是挺有意思的;最终实现的效果如下图:使用了Margin实现左右…

python之解析最简单的xml

1、person.xm文件如下 2、用xml.etree.ElementTree解析person.xml的实现 3、效果如下 4、总结 python里面的list []相当于java里面的list&#xff0c;然后可以改变其中的值。

mysql忘记密码,怎么办?

mysql忘记密码&#xff0c;怎么办&#xff1f;我们经常需要修改mySQL的密码&#xff0c;比如时间久了忘记了MySQL的密码&#xff0c;也或者是使用了一台别人使用过的电脑&#xff0c;不知道之前密码的情况下&#xff0c;又想使用MySQL&#xff0c;怎么办呢&#xff1f;准备工作…

三分钟学会缓存工具DiskLruCache

DiskLruCache是一个十分好用的android缓存工具&#xff0c;我们可以从GitHub上下载其源码&#xff1a;https://github.com/JakeWharton/DiskLruCache DiskLruCache所有的数据都存储在/storage/emulated/0/Android/data/应用包名/cache/XXX文件夹中(你也可以修改&#xff0c;但不…

【数据挖掘】知识总结——背景、定义、一般流程及应用(一)

数据挖掘知识总结&#xff08;一&#xff09; 1.数据挖掘产生的背景&&驱动力 DRIP&#xff08;Data Rich Information Poor&#xff09; 四种主要技术激发了人们对数据挖掘技术的开发、应用和研究的兴趣&#xff1a; 超大规模数据库的出现&#xff0c;如商业数据仓…