Java与模式-外观模式
来源:互联网 发布:淘宝小卖家还能做吗 编辑:程序博客网 时间:2024/05/18 20:11
/* 挂号的示意性代码 */class Register {public void doRigister() {System.out.println("挂号成功,请去门诊候诊!");}}/*诊断的示意性代码*/class Diagnose {public void doDiagnose() {System.out.println("诊断完毕,请去划价!");}}/*划价的示意性代码*/class Charge {public void doCharge() {System.out.println("成功划价!");}}/*取药的示意性代码*/class Medicines {public void doMedicines() {System.out.println("红色药丸一天三次,一次三粒");}}/*办理住院手续的示意性代码*/ class BeInHospital {public void doIn() {System.out.println("办理主元素后续");}}/*使用CT检查的示意代码*/class CT {public void doCT() {System.out.println("CT预约成功!");}}病人对应着客户端:
/*在当前环境下,病人看病的流程*/class Patient {public static void main(String[] args) {System.out.println("---来到医院,茫然无措,不知道该做什么,很是恐慌---");//挂号new Register().doRigister();//门诊new Diagnose().doDiagnose();//划价new Charge().doCharge();//取药new Medicines().doMedicines();}}
我们可以看到,为了完成看病的流程,客户端不得不去跟系统中的一个个模块去打交道,客户端必须得掌握各个模块,同时又很模块耦合的很紧密,一旦某个模块发生变化,客户端也要相应的改变。这可不是好的设计思路。用图来表示上面的例子会更直观一些
:
如果医院能派一个人来专门负责这些事情,或者提供一个绿色通道,只在一个地方办一次手续就完成了大部分的工作,如果是这样的话,那这个病人无疑会稍稍幸福一些。比如现在看病的流程是这样:
如果把上面的情形放到软件系统中就得到一个设计模式。
外观模式
有几个词需要说明一下,外观,视图,接口,当我们说外观、视图时不是说图形界面,而是说从外面看一个模块或者类时,我们能看到的内容,也许上面的话来形容接口更恰当,这里的接口不是指Java中的interface,而是Java中的类(或者接口)中暴露于外的内容,比如public的内容。还以上面的例子来说明,看病的具体流程就是系统中的一个模块,这些模块组合在一起就是一个子系统,外观定义了子系统的一个接口,也就是客户端通过外观能看到的内容。下面给出外观模式的定义:外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
在没有使用外观模式的看病流程中有两个缺点:客户端必须要掌握很多模块;客户端和各个模块耦合紧密。使用了外观模式之后,客户端只要通过外观模式就能得到想要的内容,简化了学习难度,没有必要去掌握各个模块的细节。同时,外观还使客户端和各个模块解耦,在以后如果模块发生了变化,这些变化会被外观接口消化,客户端不会感知这种变化。外观模式的优点:提供统一的接口,简化访问;将客户与子系统解耦。这其实也是外观模式的本质:封装交互,简化调用。
使用外观模式来重写上面的例子,各个模块无需重写,我们需要增加一个外观类:
/*外观类,给客户端提供了一个视图,它应该是个单例类*/public class Facade {private static class Holder {private static Facade instance = new Facade();}public static Facade getInstance() {return Holder.instance;}/*缺省实现,对大多数人来说足够*/public void doDefault() {//挂号new Register().doRigister();//门诊new Diagnose().doDiagnose();//划价new Charge().doCharge();//取药new Medicines().doMedicines();}public void doAll(boolean isCT) {//挂号new Register().doRigister();//门诊new Diagnose().doDiagnose();if(isCT) {new CT().doCT();}//划价new Charge().doCharge();//取药new Medicines().doMedicines();}}这个时候客户端在去调用就会很简单了:
class Patient {public static void main(String[] args) {System.out.println("---使用了外观模式之后---");Facade facade = Facade.getInstance();facade.doDefault();//客户端还是可以直接使用各个模块Medicines m = new Medicines();m.doMedicines();}}说明
外观接口没有给子系统增加任何新的功能,外观的目的是提供一个高层的接口,方便客户端调用,同时将模块与客户端解耦。对于客户端的请求,外观接口还是调用具体的模块去执行,它相当于一个代理。对于客户端而言,外观接口是子系统的一个视图,但是对于具体的模块而言,外观接口相当于客户端。也就是说,外观接口需要知道各个模块的存在,要掌握的它们的细节,但是具体的模块并不知道外观接口的存在。从语法上讲,可以在外观接口上增加一些额外的功能,但是这并不是外观接口的本意。
客户端可以绕过外观接口去访问具体的模块,以实现特别的功能。外观封装了一个缺省的实现,这个实现对于大多数人来说已经足够了,同时又简化了学习难度,只要知道外观接口就可以正确的使用子系统。但是对于有特别需求的客户而言,他们完全可以调用具体的模块进行更精确的控制。
可以为子系统实现一个以上的外观,但是过多的外观会引起混乱,客户端不知道到底该调用哪个外观,或者是直接调用具体模块。
最少知识原则(迪米特原则)
最少知识原则:只和你的密友谈话。它告诉我们要减少对象之间的交互,只留下几个“密友”。也就是说,当你在设计一个系统时,不管是任何对象 ,你都要注意它所交互的类有哪些,并注意它和这些类是怎么交互的。这个原则希望我们在设计中,不要让太多的类耦合到一起,免得修改系统中的一部分,会影响其他部分。就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:
(i) 该对象本身的方法
(ii) 被当做方法的参数传递进来的对象的方法
(iii) 该对象持有对象的方法
(iiii)此方法创建的对象的方法
使用最少知识原则可以减少对象之间的依赖,但是会导致更多的包装类被引入进来。
在外观模式中就遵循了最少知识原则,客户端只有外观接口这一个朋友,成功的与具体模块解耦,这样子系统可以在不影响客户端的情况下进行修改,这些改变都会被外观模式所消化。
使用场景
1)为一个复杂的子系统提供一个简单的接口
2)提供子系统的独立性,将子系统与其他的部分解耦
3)在层次系统中,可以使用外观模式定义每一层的入口
4)在维护旧系统时,如果有新的功能依赖原来的模块,这个时候可以将外观模式应用到旧系统中,新的功能只从外观接口中获得功能,对旧系统的维护和修改不会影响新功能的调用。
外观模式提供了一个高层的接口,它帮助客户容易的调用子系统,同时将客户端与子系统解耦,它不会增加新的功能,客户端也可以绕过它去访问底层的模块,因为外观模式的存在,客户变得简单而又富有弹性。
转载请注明出处:喻红叶《Java与模式-外观模式》
- Java与模式-外观模式
- <JAVA与模式>之外观模式
- 适配器模式与外观模式
- 策略模式与外观模式
- 适配器模式与外观模式
- 适配器模式与外观模式
- 适配器与外观模式
- Java设计模式---外观模式
- java设计模式--外观模式
- java模式之外观模式
- java设计模式----外观模式
- Java 设计模式- 外观模式
- java设计模式-外观模式
- java设计模式-外观模式
- Java设计模式--外观模式
- java设计模式,外观模式
- JAVA设计模式(外观模式)
- JAVA设计模式--外观模式
- Asce's Summer Ranking No.5
- Linux CentOs6手动编译wine安装时提示缺少 Xlib/Xfree86 解决办法
- Windows开启SNMP服务----Win7
- 阿斯顿发生大幅阿斯顿发
- C语言数据结构-3.栈的顺序及链式存储结构
- Java与模式-外观模式
- hdu1213
- foj 1692 矩阵快速幂&&循环矩阵优化
- Lake Countinge的s
- poj 2299
- Cocos2d-x开发实例:使用Lambda 表达式
- POJ1979 FLIP GAME (DFS&BFS都可以)
- leetcode Sort List(**)
- Ctype.h 中isdigit 函数的使用 HDU2017 字符串