外观方式(Facade)
外观模式(Facade)
外观模式(Facade)
还是从《Head First Design Patterns》中的例子说起(我重新整理了那个例子),
例子是这样描述的,说是美国有很多人搞家庭影院(我考虑一种最简单的方式,也就是全部是打开和关闭),
在家庭影院中,首先必须要有灯光,屏幕,投影机,功放机,DVD 播放器这几个基本的工具,
而灯光呢可以关闭灯光,打开灯光,
投影机呢,可以打开和关闭投影机,
屏幕呢,也可以打开和关闭,
功放机的话,关闭音量,打开音量,
DVD 播放器的话可以打开播放器和关闭播放器。
以最普通的方式来实现观看电影的话,估计类图会如下所示:
然后我要打开看电影的话,我必须在客户端执行下面的操作,
先打开投影仪,再打开功放机,再打开屏幕,再打开 DVD 播放机,再打开灯光,
在经历了这么多操作后,您才可以看一场电影(看得多不爽啊,居然这么多操作,太复杂了),
而后在关闭的时候,你还是要先关闭投影仪,再关闭功放机,再关闭屏幕,再关闭 DVD 播放机,再关闭灯光,
哦,这是太复杂了!!!
在客户端居然有那么多操作(问题是还有一些用户可能不知道如何使用其中的一个工具那他便看不了电影),
用户简直会烦死去!!!
上面其实反映的是一个现今软件开发系统中的一个比较常见的现象,
那就是客户端程序经常和复杂系统的内部子系统产生直接联系,而导致客户程序随着子系统的变化而变化。
而上面的例子中呢,客户端程序便是用户的操作,而复杂系统的内部子系统代表的就是这些工具的一些使用接口。
上面的例子中我还只是使用了最简单的工具操作接口,即简单的打开和关闭,
如果在子系统,即各个工具中还有新的功能的话呢?
那么必然会导致客户端代码得变化。
要想解决上面的这一串问题,
你必须要简化客户程序与子系统之间的交互接口(要使得不会使用所有工具的用户也可以实现观看电影),
然后就是要解除客户程序和子系统之间的耦合,而外观模式正好可以解决这个问题。
外观模式(Facade)的定义
为子系统中的一组接口提供一个一致的界面,用来访问子系统中的一群接口,
此模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。
简单的说,就是外观模式将一个或者多个类的复杂的操作进行了隐藏,只显示出一个一致的界面供客户端使用。
还有需要注意的是,外观模式仅仅是给你提供了更为直接和容易的操作方式,它并没有把原来的子系统进行隔离,
所以,如果你还需要子系统类的更高层的功能,还是可以使用原来的子系统的,这个是外观模式的一大优点。
同时,通过外观模式可以子系统的多个接口上建立一个高层接口,并且将这个高层接口提供给客户端使用,
这样便可以解除掉客户端和复杂子系统之间的耦合。
同时,外观模式也可以使我们遵循迪米特法则(也就是最小知识原则)。
过外观模式可以实现提供简单的接口(OpenMovie 和 CloseMovie)给客户端,
也给客户端和子系统之间实现了解耦。
Facade一个典型应用就是数据库JDBC的应用(这里就不举例了)
举个例子
我们把一个文件,放在了第二抽屉里,而第二个抽屉的钥匙放在了第一个抽屉里,我们要想取出这个文件,第一步肯定要拿到第一个抽屉的钥匙,然后打开它再拿出第二个抽屉的钥匙,最后打开第二个抽屉取出文件。(两个抽屉还好说,但如果是n个呢?)所以对于客户来说,这些取钥匙的过程不需要知道,他们只需要按一个按钮,然后文件就自动取出来。代码例子如下:
public class DrawerOne {
public void open() {
System.out.println("第一个抽屉被打开了");
getKey();
}
public void getKey() {
System.out.println("得到第二个抽屉的钥匙");
}
}
public class DrawerTwo {
public void open() {
System.out.println("第二个抽屉被打开了");
getFile();
}
public void getFile() {
System.out.println("得到这个重要文件");
}
}
//这就是外观类,对客户隐藏了所有具体细节
//client类只需要调用一个open()就完成所有操作
public class DrawerFacade {
DrawerOne darwerOne = new DrawerOne();
DrawerTwo darwerTwo = new DrawerTwo();
public void open() {
darwerOne.open();
darwerTwo.open();
}
}
public class Client {
public static void main(String[] args) {
DrawerFacade drawer = new DrawerFacade();
drawer.open();
}
}
输出结果:
第一个抽屉被打开了
得到第二个抽屉的钥匙
第二个抽屉被打开了
得到这个重要文件
外观模式(Facade)
还是从《Head First Design Patterns》中的例子说起(我重新整理了那个例子),
例子是这样描述的,说是美国有很多人搞家庭影院(我考虑一种最简单的方式,也就是全部是打开和关闭),
在家庭影院中,首先必须要有灯光,屏幕,投影机,功放机,DVD 播放器这几个基本的工具,
而灯光呢可以关闭灯光,打开灯光,
投影机呢,可以打开和关闭投影机,
屏幕呢,也可以打开和关闭,
功放机的话,关闭音量,打开音量,
DVD 播放器的话可以打开播放器和关闭播放器。
以最普通的方式来实现观看电影的话,估计类图会如下所示:
然后我要打开看电影的话,我必须在客户端执行下面的操作,
先打开投影仪,再打开功放机,再打开屏幕,再打开 DVD 播放机,再打开灯光,
在经历了这么多操作后,您才可以看一场电影(看得多不爽啊,居然这么多操作,太复杂了),
而后在关闭的时候,你还是要先关闭投影仪,再关闭功放机,再关闭屏幕,再关闭 DVD 播放机,再关闭灯光,
哦,这是太复杂了!!!
在客户端居然有那么多操作(问题是还有一些用户可能不知道如何使用其中的一个工具那他便看不了电影),
用户简直会烦死去!!!
上面其实反映的是一个现今软件开发系统中的一个比较常见的现象,
那就是客户端程序经常和复杂系统的内部子系统产生直接联系,而导致客户程序随着子系统的变化而变化。
而上面的例子中呢,客户端程序便是用户的操作,而复杂系统的内部子系统代表的就是这些工具的一些使用接口。
上面的例子中我还只是使用了最简单的工具操作接口,即简单的打开和关闭,
如果在子系统,即各个工具中还有新的功能的话呢?
那么必然会导致客户端代码得变化。
要想解决上面的这一串问题,
你必须要简化客户程序与子系统之间的交互接口(要使得不会使用所有工具的用户也可以实现观看电影),
然后就是要解除客户程序和子系统之间的耦合,而外观模式正好可以解决这个问题。
外观模式(Facade)的定义
为子系统中的一组接口提供一个一致的界面,用来访问子系统中的一群接口,
此模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。
简单的说,就是外观模式将一个或者多个类的复杂的操作进行了隐藏,只显示出一个一致的界面供客户端使用。
还有需要注意的是,外观模式仅仅是给你提供了更为直接和容易的操作方式,它并没有把原来的子系统进行隔离,
所以,如果你还需要子系统类的更高层的功能,还是可以使用原来的子系统的,这个是外观模式的一大优点。
同时,通过外观模式可以子系统的多个接口上建立一个高层接口,并且将这个高层接口提供给客户端使用,
这样便可以解除掉客户端和复杂子系统之间的耦合。
同时,外观模式也可以使我们遵循迪米特法则(也就是最小知识原则)。
过外观模式可以实现提供简单的接口(OpenMovie 和 CloseMovie)给客户端,
也给客户端和子系统之间实现了解耦。
Facade一个典型应用就是数据库JDBC的应用(这里就不举例了)
举个例子
我们把一个文件,放在了第二抽屉里,而第二个抽屉的钥匙放在了第一个抽屉里,我们要想取出这个文件,第一步肯定要拿到第一个抽屉的钥匙,然后打开它再拿出第二个抽屉的钥匙,最后打开第二个抽屉取出文件。(两个抽屉还好说,但如果是n个呢?)所以对于客户来说,这些取钥匙的过程不需要知道,他们只需要按一个按钮,然后文件就自动取出来。代码例子如下:
public class DrawerOne {
public void open() {
System.out.println("第一个抽屉被打开了");
getKey();
}
public void getKey() {
System.out.println("得到第二个抽屉的钥匙");
}
}
public class DrawerTwo {
public void open() {
System.out.println("第二个抽屉被打开了");
getFile();
}
public void getFile() {
System.out.println("得到这个重要文件");
}
}
//这就是外观类,对客户隐藏了所有具体细节
//client类只需要调用一个open()就完成所有操作
public class DrawerFacade {
DrawerOne darwerOne = new DrawerOne();
DrawerTwo darwerTwo = new DrawerTwo();
public void open() {
darwerOne.open();
darwerTwo.open();
}
}
public class Client {
public static void main(String[] args) {
DrawerFacade drawer = new DrawerFacade();
drawer.open();
}
}
输出结果:
第一个抽屉被打开了
得到第二个抽屉的钥匙
第二个抽屉被打开了
得到这个重要文件