这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
前言
周末学习,一晃时间又过了半个多月,最近时间比较紧,而设计模式的学习是个细水长流的过程,急躁不得,这周有时间,就花了两个多小时写下了这篇文章,它就是结构型模式的第五种----外观模式。
一、外观模式入门
1.1 概述
体检的经历想必大家都经历过吧,而这个过程其实就可以联想到我们今天要讲的外观模式。(在写这篇文章的时候,又拿起体检报告看了下,心里嘀咕句:xdm,注意健康啊!)
一般体检过程就是我们根据网上预定的日期空腹去体检中心。根据预定的项目,有一般检查、内科、外科、眼科、彩超、心电图、血常规、尿常规等等项目。
而我们往往第一次去是不知道这些房间是在哪里的,所以,我们一般会去求助现场的接待人员,通过它分别找到我们的体检目标具体位置,这一过程可以看做外观模式,也称门面模式。
ok,理解了它的含义,我们来看看它的专业讲解。
维基百科定义:
外观模式(Facade pattern),是软件工程中常用的一种软件设计模式,它为子系统中的一组界面提供一个统一的高层界面,使得子系统更容易使用。
它是一种结构型设计模式,能为程序库、框架或其他复杂类提供一个简单的接口。又名门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
外观(Facade)模式是“迪米特法则”的典型应用,也就是之前举的明星和经纪人的例子。
1.2 结构
下面是外观模式的一个通用的结构,如果没有 ”接待员“ 这个角色,我们可能会满医院乱跑,而通过这样的 ”门面“ 存在,我们只负责和它打交道即可,通过它可以实现我们的目的。
而外观模式的角色也非常的简单:
- 外观角色(Facade)角色:为多个子系统对外提供一个共同的接口
- 子系统角色:实现系统的部分功能,客户可以通过外观角色访问它。
通过这两个角色,可以达到下面的目的:
- 1、引入外观角色之后,用户只需要和外观角色交互
- 2、用户与子系统之间的复杂逻辑关系由外观角色来实现
二、案例讲解
这里,我们来把这个体检的案例来用代码实现一下吧。
定义三个体检项目,和一个接待人员,一个测试类。
/**
* 内科
**/
public class InternalMedicine {
public void here(){
System.out.println("内科未见异常");
}
}
/**
* 眼科
**/
public class Ophthalmology {
public void here(){
System.out.println("眼科注意保养!");
}
}
/**
* 外科
**/
public class Surgical {
public void here(){
System.out.println("外科未见异常");
}
}
/**
* 接待人员
**/
public class Receptionist {
private InternalMedicine inner;
private Ophthalmology eye;
private Surgical out;
public Receptionist(){
inner=new InternalMedicine();
eye =new Ophthalmology();
out=new Surgical();
}
public void say(String message){
if(message.equals("我要体检")){
this.gohere();
}
}
private void gohere() {
System.out.println("欢迎来到我们体检中心!!! 体检项目在那,去吧~");
inner.here();
eye.here();
out.here();
}
}
复制代码
输出结果:
欢迎来到我们体检中心!!! 体检项目在那,去吧~
内科未见异常
眼科注意保养!
外科未见异常
复制代码
三、模式分析
3.1 优缺点
优点:
- 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类,你可以让自己的代码独立于复杂子系统。
缺点:
- 不符合开闭原则,所有类都耦合在一起,修改很麻烦。
3.2 使用场景
- 1、当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
- 2、引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。
- 3、在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
3.3 外观模式与适配器模式区别
适配器模式是将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作互通。
外观模式是提供一个统一的高层接口,用来访问子系统的一群接口,让子系统更好用点。
简而言之: 适配器模式职责是将一个对象接口 转换不同接口 外观模式职责是 将多个对象包装起来提供一个统一的接口来简化接口
3.4 需要注意的点
- 一个系统有多个外观类
在外观模式中,通常只需要一个外观类,并且此外观类只有一个实例,换言之它是一个单例类。在很多情况下为了节约系统资源,一般将外观类设计为单例类。当然这并不意味着在整个系统里只能有一个外观类,在一个系统中可以设计多个外观类,每个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能。
- 不要试图通过外观类为子系统增加新行为
不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增加应该通过修改原有子系统类或增加新的子系统类来实现,不能通过外观类来实现。
- 外观模式与迪米特法则
外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,降低了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器。
- 抽象外观类的引入
外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。
3.5 小结
外观模式比较简单理解,它通过与门面打交道,避免了与下面各个复杂子系统的操作,从而达到简化系统的目的,让这个复杂的系统变得容易使用。如果能够合理的使用外观模式,可以帮助我们更好的划分访问的层次,隐藏一些复杂细节到子系统,留个简单粗暴的接口给外观展示,外观模式,就这么简单!
最后,祝愿兄弟们都能体检指标样样合格,检查结果样样达标。
设计模式本身在应用中是有一定难度的,需要一定的业务经验积累,如果哪一天你在哪个底层源码中突然领略到哪个你看过的模式,就值了,如果哪一天,你在面对业务捉急的时候,突然把脑门一拍,哎,要不试试外观模式,那你可能就顿悟了,希望那一天离你更近一点。我是潇雷,如果你觉得本文对你有帮助或启发,帮忙点个赞,这将是我创作的最好动力!
参考文档: