终于考试完了,瞬间感觉轻松了许多,又可以安心地写代码了,下面进入今天的正题–外观模式。
外观模式,也称门面模式,顾名思义,就是一个对象封装了一系列相关的操作(行为),使得这些操作仅对外提供(暴露)方法(接口),客户端根据这些外观(暴露的接口)就可以简单地完成一系列操作,达到了客户端无需知道内部实现细节,只需知道对象的外观就可以实现一系列行为,简单来说就是面向对象的封装。这一系列行为也就是一个系统的功能。
定义:通过一个统一的对象实现一个系统的外部与内部的通讯,提供了一个高层次的接口,使得系统功能更加透明,更加容易使用。
使用场景:
1.
为一个复杂系统提供一个简单的接口。为一个复杂系统提供一个简单的接口,对外部隐藏系统的内部实现,隔离变化,使得当这个系统因为不断演化而不断的修改,定制也可以更加容易地扩展使用,即对外部的使用是一样的,客户端无需知道内部发生了什么变化,隐藏了系统的内部实现,这也就是封装的好处了。
1.
简化子系统之间的依赖,降低它们之前的耦合。当不同的子系统需要使用其他系统的功能的时候,那么我们就需要构建一个层次结构的系统,这时我们通过外观模式为这些子系统提供一个通讯接口,即每层的入口点。
优点:
1.
因为对客户端隐藏了系统的细节,减少了客户端对于系统的耦合,能够拥抱变化。
1.
对系统一系列功能进行了整合,封装,使得系统更加容易使用。
缺点:
1.
外观类接口膨胀。因为我们外观类需要封装一系列相关的功能,这一系列相关的功能可能需要不同的类实现,那么我们不是简单地给这个外观类提供实现不同功能类,而是为每个实现不同功能的类提供一个接口,然后再使用的时候给这些接口提供实现类,这样可以便于扩展,反之,外观类接口必然膨胀,也增加了程序员的一定的负担。
1.
违背了开闭原则,当业务出现变更的时候,可能需要直接修改外观类(通常是修改外观类中的接口的实现类)。
下面以现代智能机模拟实现外观模式
代码实现:
虚拟手机(接口)—-接打电话功能接口
~~~
public interface Phone {
/**
* 打电话
*/
public void call();
/**
* 挂断
*/
public void handup();
}
~~~
虚拟相机(接口)—-拍照功能接口
~~~
/**
* 照相机
* @author lt
*
*/
public interface Camera {
public void open();
public void takePicture();
public void close();
}
~~~
真实的手机(实现类)
~~~
/**
* 以前的旧手机,非智能,只能打电话和挂电话
* @author lt
*
*/
public class PhoneImpl implements Phone{
@Override
public void call() {
System.out.println("打电话");
}
@Override
public void handup() {
System.out.println("挂断电话");
}
}
~~~
真实的相机(实现类)
~~~
/**
* 三星相机
* @author lt
*
*/
public class SamsungCamera implements Camera{
@Override
public void open() {
System.out.println("打开相机");
}
@Override
public void takePicture() {
System.out.println("拍到了一个美女");
}
@Override
public void close() {
System.out.println("相机关闭了");
}
}
~~~
现代智能机(Android/Iphone)—-外观类
~~~
/**
* 现代智能机 --- 集照相,视频聊天,打电话于一身
* @author lt
*
*/
public class SmartPhone {
// 对应实现完成手机功能接口的实现类
public Phone phone = new PhoneImpl();
// 对应实现相机功能接口的实现类
public Camera camera = new SamsungCamera();
public void call() {
phone.call();
}
public void hangup() {
phone.handup();
}
public void takePicture() {
openCamera();
camera.takePicture();
closeCamera();
}
public void openCamera() {
camera.open();
}
public void closeCamera() {
camera.close();
}
/**
* 视频通话
*/
public void videoChat() {
openCamera();
System.out.println("和妹子视频聊天");
closeCamera();
}
}
~~~
SmartPhone是外观类,这里具体是现代智能机,具有接打电话,拍照等功能,是这个模式核心类;Phone和Camera是两个特定功能的接口,分别是接打电话的功能,拍照功能,相应的实现类是PhoneIml和SamsungCamera。这里给外观类整了两个接口,即Phone和Camera,这样做的目的是以后要修改接打电话和拍照功能的实现时(如新的硬件)只需要将外观类SmartPhone中的相应功能的接口实现类改变一下就可以了,其他的都不用改,这也就是面向接口编程的好处,和J2EE中的Service,Dao层都提供一个接口和相应实现类一样,目的是一样的,即便于修改扩展。
测试:
~~~
public class Test {
public static void main(String[] args) {
SmartPhone iphone7s = new SmartPhone();
// 用7s拍照
iphone7s.takePicture();
// 用7s视频聊天
iphone7s.videoChat();
}
}
~~~
运行结果:
![这里写图片描述](https://box.kancloud.cn/2016-03-17_56ea5b37e63ed.jpg "")
可以看到,现代的智能机既有一般手机的功能,也有相机的功能,使得我们只需要一部智能机就不需要专门为打电话买一个手机,专门为拍照买一个相机了,一部手机统统搞定,而且避免了许多麻烦,如我们点击屏幕的相机(系统内置App)系统自动打开了相机,拍照完了以后系统自动将相机关闭,视频聊天也一样,这使得我们使用更加简单,更加方便。
总结:
外观模式使用也非常多,面向对象中的封装也通常是使用了外观模式,封装不一定使用了外观模式,但外观模式一定需要封装。通过外观模式,使得复杂系统功能更加丰富,使用更加简单。通过一个外观类就可以操作整个系统,减少了用户的使用成本,同时因为内部面向接口编程,使得使扩展维护更加简单,从而使得系统可以容易地面对多变的场景,提升了系统的扩展性灵活性。