背景
在某个系统下,如果子模块比较多,而且内部的细节也比较多,这时调用这些子模块就会比较麻烦。这时外观模式就应运而生,系统会提供一个外观者,由它来调用各个子模块的各个步骤,而使用者去调用外观者的方法就可。
角色
子模块:处理外观者指派的任务,它是功能的实际提供者
外观者:为调用者提供封装好的接口,屏蔽子模块的细节,接口内部请求各个子模块的方法
调用者:外观者的调用方
代码举例
将一个家庭影院映射到编程中,家庭影院有爆米花机、屏幕、投影仪、DVD播放器(各个子模块);提供一个遥控器(外观者),有准备、开始播放、关闭三个按钮。
爆米花机类:
/**
* 爆米花机
*/
public class Popcorn {
private static Popcorn instance = new Popcorn();
private Popcorn(){}
public static Popcorn getInstance() {
return instance;
}
public void on() {
System.out.println("打开爆米花机");
}
public void pop() {
System.out.println("开始爆");
}
public void off() {
System.out.println("关闭爆米花机");
}
}
屏幕类:
/**
* 屏幕
*/
public class Screen {
private static Screen instance = new Screen();
private Screen(){}
public static Screen getInstance() {
return instance;
}
public void down() {
System.out.println("放下屏幕");
}
public void up() {
System.out.println("升起屏幕");
}
}
投影仪类:
/**
* 投影仪
*/
public class Projector {
private static Projector instance = new Projector();
private Projector(){}
public static Projector getInstance() {
return instance;
}
public void on() {
System.out.println("打开投影仪");
}
public void focus() {
System.out.println("投影仪聚焦");
}
public void off() {
System.out.println("关闭投影仪");
}
}
DVD播放器类:
public class DVDPlayer {
private static DVDPlayer instance = new DVDPlayer();
private DVDPlayer(){}
public static DVDPlayer getInstanc() {
return instance;
}
public void on() {
System.out.println("打开DVD");
}
public void play() {
System.out.println("播放DVD");
}
public void off() {
System.out.println("关闭DVD");
}
}
遥控器类:
/**
* 遥控器类
*/
public class RemoteControl {
//定义各个子系统对象
private Popcorn popcorn;
private Screen screen;
private Projector projector;
private DVDPlayer dVDPlayer;
//构造器
public RemoteControl() {
this.popcorn = Popcorn.getInstance();
this.screen = Screen.getInstance();
this.projector = Projector.getInstance();
this.dVDPlayer = DVDPlayer.getInstanc();
}
//操作分成 4 步
public void ready() {
popcorn.on();
popcorn.pop();
screen.down();
projector.on();
projector.focus();
dVDPlayer.on();
}
public void play() {
dVDPlayer.play();
}
public void end() {
popcorn.off();
screen.up();
projector.off();
dVDPlayer.off();
}
}
测试类:
public class Test {
public static void main(String[] args) {
RemoteControl control = new RemoteControl();
control.ready();
System.out.println("-----");
control.play();
System.out.println("-----");
control.end();
}
}
运行结果如下:
优势
1.对外屏蔽了子模块的细节,因此降低了客户端对子模块使用的复杂性
2.对客户端和子模块进行了解耦,使子模块更容易维护和扩展
3.合理的使用外观模式,可以帮我们更好的划分访问的层次