一、定义
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。
二、角色
- Facade:系统对外的统一接口,客户端连接子系统功能的入口
- SubSystem子系统:可以同时有一个或多个子系统,每个子系统都不是一个单独的类,而是一个类的集合。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已
三、使用场景
- 构建一个有层次结构的子系统时,使用外观模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,则可以让他们通过外观接口进行通信,减少子系统之间的依赖关系。
- 子系统往往会因为不断的重构演化而变得越来越复杂,大多数的模式使用时也会产生很多很小的类,这给外部调用他们的用户程序带来了使用的困难,我们可以使用外观类提供一个简单的接口,对外隐藏子系统的具体实现并隔离变化。
- 当维护一个遗留的大型系统时,可能这个系统已经非常难以维护和拓展,但因为它含有重要的功能,新的需求必须依赖于它,则可以使用外观类,来为设计粗糙或者复杂的遗留代码提供一个简单的接口,让新系统和外观类交互,而外观类负责与遗留的代码进行交互。
四、使用案例
生产nokia手机,分为三个步骤,设计,开发和生产来模拟整个过程
1、最高层接口
最高层接口就是为了统一API,客户端调用只需要调用设计,开发和生产三个方法举行了,具体内部实现无须关注。具体的实现由内部的子系统去完成。
public abstract class NokiaPhone {
public abstract void design();
public abstract void development();
public abstract void production();
}
public class NokiaPhoneImpl extends NokiaPhone{
private Software software = new SoftwareImpl();
private Hardware hardware = new HardwareImpl();
private Production production = new ProductionImpl();
@Override
public void design() {
hardware.design();
software.design();
}
@Override
public void development() {
hardware.development();
software.development();
}
@Override
public void production() {
hardware.test();
software.test();
production.production();
}
}
2、子系统
子系统还可以包含更多的子系统,比如软件部还有测试组、系统组等等。
硬件部
public interface Hardware {
public void design();
public void development();
public void test();
}
public class HardwareImpl implements Hardware {
private static final String TAG = HardwareImpl.class.getSimpleName();
@Override
public void design() {
Log.d(TAG,"design");
}
@Override
public void development() {
Log.d(TAG,"development");
}
@Override
public void test() {
Log.d(TAG,"test pass");
}
}
软件部
public interface Software {
public void design();
public void development();
public void test();
}
public class SoftwareImpl implements Software{
private static final String TAG = SoftwareImpl.class.getSimpleName();
@Override
public void design() {
Log.d(TAG,"design");
}
@Override
public void development() {
Log.d(TAG,"development");
}
@Override
public void test() {
Log.d(TAG,"test pass");
}
}
生产部
public interface Production {
public void production();
}
public class ProductionImpl implements Production {
private static final String TAG = ProductionImpl.class.getSimpleName();
@Override
public void production() {
Log.d(TAG,"production nokia");
}
}
3、调用
客户端和抽象类抽象出的方法一样。统一的API只有三个。具体的实现由子系统去完成。
NokiaPhoneImpl nokiaPhoneImpl = new NokiaPhoneImpl();
nokiaPhoneImpl.design();
nokiaPhoneImpl.development();
nokiaPhoneImpl.production();
五、在Android中的使用
Context
Context封装了很多操作,如startActivity(),sendBroadcast(),bindServiced()等,相当于抽象外观类
Context的子系统中去实现这些方法,如ActivityManagerService实现startActivity(),PackageManagerService实现包信息相关方法,ContextImpl则是Context的实现类,也就是外观类,
其内部调用这些子系统的实现,而Activity相当于客户端
public abstract class Context {
public abstract void sendBroadcast(@RequiresPermission Intent intent);
public abstract ComponentName startService(Intent service);
...
class ContextImpl extends Context {
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
六、优缺点
优点:
-
降低了客户类与子系统类的耦合度,实现松耦合关系
-
对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单
-
降低原有系统的复杂度和系统中的编译依赖性,并简化了系统在不同平台之间的移植过程
缺点:
-
在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”
-
不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。