注意:如果不想浪费时间,请一定要点我。
我们之前学过使用适配器模式可以将一个接口转化成用户期望的另一个接口,我们今天看的新模式是将为了简化接口,它将一个或者数个类的复杂的一切隐藏在背后,只显露出一个干净美好的外观。
定义
通过为多个复杂的子系统提供一个一致的接口,而是这些子系统更加容易使用。
外观模式是迪米特法则的典型应用,它主要有以下优点:
(1)由于客户不是直接使用子系统,降低了子系统和用户的耦合度,使得子系统的变化对用户来说是透明的。
(2)对用户隐藏了子系统的复杂情况,使得用户更加容易使用。
但是外观模式违背了开闭原则,因为每增加一个子系统,都必须修改外观类。-
外观模式的结构和实现
外观模式主要是定义了一个高层接口,它包含了多个子系统的引用,客户端可以通过它访问各个子系统的功能。
外观模式主要包括以下主要角色:
(1)外观角色:为多个子系统对外提供了一个共同的接口。
(2)子系统角色:实现系统的部分功能,客户可以通过外观角色访问它。
外观模式
比如我们想在家看一步电影,我们必须执行一些任务。
(1)打开爆米花机开始爆米花。
(2)关灯。
(3)打开投影机,选择合适的宽度。
(4)打开播放器,选择电影,然后开始播放。
不止如此,在你看完电影,还得将这一切收拾掉,我们将这些写成类和方法的调用,看看播放电影,我们到底需要做多少工作。
class Light{
public void turnOff() {
System.out.println("关灯");
}
public void turnOn() {
System.out.println("开灯");
}
}
class PopcornMachine{
public void popper() {
System.out.println("打开爆米花机,并开始爆米花");
}
public void unPopper() {
System.out.println("关闭爆米花机");
}
}
class Projector{
public void turnOn() {
System.out.println("打开投影仪");
}
public void adjust() {
System.out.println("调整合适的屏幕大小");
}
......
}
class Player{
public void turnOn() {
System.out.println("打开播放器");
}
public void chooseMovie() {
System.out.println("选择合适的电影,然后播放");
}
......
}
class People{
public void watchMoveAtHome() {
PopcornMachine pm = new PopcornMachine();
Light lt = new Light();
Projector pj= new Projector();
Player pl = new Player();
pm.popper();
pj.turnOn();
pj.adjust();
lt.turnOff();
pl.turnOn();
pl.chooseMovie();
}
}
看完电影,我们同样需要关闭播放器、投影仪、开灯等等很多的工作。所以,我们只需要使用外观模式,将这些复杂的操作隐藏在一个接口中更容易使用,对我们来说我们不必了解子系统是如何运作的。如下所示,我们可以定义一个类,通过该类对底层子系统进行调用,我们只需要使用该外观类提供的简单接口即可。
class HomeMoivePlay{
PopcornMachine pm = new PopcornMachine();
Light lt = new Light();
Projector pj= new Projector();
Player pl = new Player();
public void playMoive() {
pm.popper();
pj.turnOn();
pj.adjust();
lt.turnOff();
pl.turnOn();
pl.chooseMovie();
}
......
}
class People{
public void watchMovie(){
HomeMoivePlay hmp = new HomeMoivePlay();
hmp.playMoive();
}
}
外观模式的应用场景
(1)在设计初期,应该有意识的将不同的两个层分离,比如典型的三层架构,层与层之间建立外观,使得耦合度大大降低。
(2)在开发阶段,子系统因为系统的逐渐完善变得越来越复杂,给外部调用的用户带来了巨大的困扰,所以可以定义一个外观,提供一个简单的接口供用户使用。
(3)在维护一个遗留的大型系统时,可能该系统已经变的难以维护和扩展,但是新的系统必须和该系统进行交互,因为该系统包含重要的功能,所以可以为遗留的系统设计一个外观类,使新系统直接和该外观类进行交互。关于外观模式的一些问题
(1)外观系统中,用户如何接触最底层的子系统?
外观系统并没有 "封装" 子系统,只是提供了一个简化的接口,如果用户想要直接使用底层功能,依然可以直接使用子系统。
(2)除了提供一个简化的接口,外观模式还有没有其他的优点?
外观模式使得用户和子系统解耦,如果客户端实现是针对外观而不是针对子系统编写时,当子系统变化不需要修改客户端,直接修改外观类即可,比如看电影的过程中加了一个新的行为买可乐。客户端并不需要修改。
(3)外观会新增功能吗?还是直接负责请求转发?
外观模式当然可以新增功能,使子系统的使用更加方便。
(4)可以说,外观模式和适配器模式的差异在于适配器包装一个类,而外观包装多个类?
这句话不对,适配器也可以适配多个类,外观也可以为一个有复杂接口的类提供简化的接口,他们的意图不同,适配器模式的意图在于转化接口,而外观在于简化接口。