> 文章列表 > 设计模式:外观模式

设计模式:外观模式

设计模式:外观模式

一、定义

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。

二、角色

  • Facade:系统对外的统一接口,客户端连接子系统功能的入口
  • SubSystem子系统:可以同时有一个或多个子系统,每个子系统都不是一个单独的类,而是一个类的集合。每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已

三、使用场景

  • 为复杂的模块或子系统提供外界访问的接口,对外隐藏子系统的具体实现、隔离变化;

  • 子系统相对独立,当需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点。如果子系统间是相互依赖的,就可以让它们仅通过Facade接口进行通信,从而简化它们之间的依赖关系。

四、使用案例

生产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();@Overridepublic void design() {hardware.design();software.design();}@Overridepublic void development() {hardware.development();software.development();}@Overridepublic 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();@Overridepublic void design() {Log.d(TAG,"design");}@Overridepublic void development() {Log.d(TAG,"development");}@Overridepublic 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();@Overridepublic void design() {Log.d(TAG,"design");}@Overridepublic void development() {Log.d(TAG,"development");}@Overridepublic 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();@Overridepublic 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 {@Overridepublic 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();}}@Overridepublic ComponentName startService(Intent service) {warnIfCallingFromSystemProcess();return startServiceCommon(service, false, mUser);}

六、优缺点

优点:

  • 降低了客户类与子系统类的耦合度,实现松耦合关系

  • 对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单

  • 降低原有系统的复杂度和系统中的编译依赖性,并简化了系统在不同平台之间的移植过程

缺点:

  • 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则” 

  • 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。

英文字体