外观模式
什么是外观模式?
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。外观模式提供一个高层次的接口,使得子系统更易于使用。
动机
将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一是就是引入一个外观(facade)对象,它为子系统中较一般的设施提供了一个单一而简单的界面。(出自《设计模式:可复用面向对象软件的基础》)。
结构与角色
- 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
- 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
- 客户(Client)角色:通过一个外观角色访问各个子系统的功能。
协作
客户想要访问子系统的功能要通过外观对象去实现,而不是直接去访问子系统。
效果
优点
- 对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
- 降低了客户端与子系统类的耦合度,实现了子系统与客户之间的松耦合关系。
- 外观类对子系统的接口封装,使得系统更易于使用。
- 提高灵活性,不管子系统如何变化,只要不影响门面对象,就可以自由修改。
缺点
- 不能很好地限制客户使用子系统类,很容易带来未知风险。
- 增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
- 不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
开发中的例子
例如我们在MVC中,Controller层去调用Service层,而不会去关系ServiceImpl的具体细节,那么Service就相当于是外观,无论ServiceImpl如何变化,都不会影响客户通过外观去使用它。只关注Service,不关注具体Service的实现。
代码实现
FacadeClass
package com.wlj.facade;
/**
* @author wlj
* @Classname FacadeClass
* @Description 外观
* @Date 7/2/2022 5:22 PM
*/
public class FacadeClass {
private SubSystem01 subSystem01 = new SubSystem01();
private SubSystem02 subSystem02 = new SubSystem02();
public void doSth(String sth ){
if(sth.equals("music")){
subSystem01.playMusic();
}
if(sth.equals("game")){
subSystem02.playGame();
}
}
}
SubSystem01
package com.wlj.facade;
/**
* @author wlj
* @Classname SubSystem01
* @Description 子系统1
* @Date 7/2/2022 5:22 PM
*/
public class SubSystem01 {
public void playMusic(){
System.out.println("子系统1上播放音乐");
}
}
SubSystem02
package com.wlj.facade;
/**
* @author wlj
* @Classname SubSystem02
* @Description 子系统2
* @Date 7/2/2022 5:31 PM
*/
public class SubSystem02 {
public void playGame(){
System.out.println("子系统2上玩游戏");
}
}
Client
package com.wlj.facade;
/**
* @author wlj
* @Classname Client
* @Description 用户
* @Date 7/2/2022 5:32 PM
*/
public class Client {
public static void main(String[] args) {
// 用户无需知道子系统具体实现细节,只需要知道外观角色即可。
FacadeClass facade = new FacadeClass();
facade.doSth("music");
facade.doSth("game");
}
}