介绍
外观模式(Facade)在开发过程中的运用频率非常高,通过一个外观类使得整个系统的接口只有一个统一的高层接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节。当然在我们实际开发过程中,外观模式也使我们封装API的常用手段。
定义
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。外观模式(Facade)提供一个高层次的接口,使得子系统更易于使用
使用场景
- 当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。
这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
- 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入 facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性 和可移植性。
- 当你需要构建一个层次结构的子系统时,使用 facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系。
UML类图
角色介绍
- Facade:系统对外的统一接口,系统内部系统地工作
- SystemA、SystemB:子系统接口
- Client:调用facade角色获得完成相应的功能。
外观模式接口比较简单,就是通过一个统一的接口对外提供服务,是得外部程序只通过一个类就可以实现系统内部的多种功能,而这些实现功能的内部子系统之间可能也有交互,或者说完成一个功能需要几个子系统之间进行协作,如果没有封装,那么用户就需要操作几个子系统的交互逻辑,容易出错,而通过外观类对外屏蔽了浙西复杂的交互,降低用户的使用成本。
优点
- 对客户程序隐藏子系统细节,因而减少了客户对于子系统的耦合,能够拥抱变化
- 外观类对于子系统的接口封装,使得系统更易于使用
缺点
- 外观类接口膨胀。由于子系统的接口都有外观类统一对外暴漏,使得外观类的API接口较多,在一定程度上增加了用户使用成本。
- 外观类没有遵循开闭原则,当业务出现变更时,可能需要直接修改外观类
示例代码
子系统接口
public interface IBase {
void init();
}
public interface IMusic extends IBase {
void doMusic();
}
public class MusicIMPL implements IMusic {
@Override
public void init() {
System.out.println("初始化音乐");
}
@Override
public void doMusic() {
System.out.println("播放音乐");
}
}
public interface IPhoto extends IBase{
void doPhoto();
}
public class PhotoIMPL implements IPhoto {
@Override
public void doPhoto() {
System.out.println("进行拍照");
}
@Override
public void init() {
System.out.println("初始化拍照");
}
}
public interface ISms extends IBase {
void doSms();
}
public class SmsIMPL implements ISms {
@Override
public void init() {
System.out.println("初始化短信");
}
@Override
public void doSms() {
System.out.println("发送短信");
}
}
Facade
public class MobilePhone {
private IMusic mMusic = new MusicIMPL();
private IPhoto mPhoto = new PhotoIMPL();
private ISms mSms = new SmsIMPL();
public void init() {
mMusic.init();
mPhoto.init();
mSms.init();
}
public void doPhoto() {
mPhoto.doPhoto();
}
public void doMusic() {
mMusic.doMusic();
}
public void doSms() {
mSms.doSms();
}
}
TestClass
public class TestFacade {
public static void main(String[] args) {
MobilePhone phone = new MobilePhone();
System.out.println("-------------------------");
phone.init();
System.out.println("-------------------------");
phone.doPhoto();
System.out.println("-------------------------");
phone.doSms();
System.out.println("-------------------------");
phone.doMusic();
System.out.println("-------------------------");
}
}
Log
-------------------------
初始化音乐
初始化拍照
初始化短信
-------------------------
进行拍照
-------------------------
发送短信
-------------------------
播放音乐
-------------------------
从上述代码中可以看到,外观模式就是一个统一的接口封装,将子系统的逻辑、交互隐藏起来,为用户提供一个高层次的接口,使得系统系统更加易用,同时也对外隐藏了具体的实现,这样即使具体的子类系统发生了变化,用户也不会感知到,因为用户使用的是Facade高层接口,内部的变化对于用户来说并不可见。这样依赖就将变化隔离开来,使得系统也更为灵活。