实例:
当客户端为了完成某个功能,需要去调用某个系统中多个模块时,例如A模块、B模块....。那么对于客户端而言,就需要知道这些个模块的功能,还需要知道如何组合这每一个模块的功能来实现自己想要的功能。它的实现代码可能是这样的:
/** * A模块 */ public interface AModuleApi{ public void testA(); } /** * B模块 */ public interface BModuleApi{ public void testB(); } public class AModuleImpl implements AModuleApi { @Override public void testA() { System.out.println("A模块操作"); } } public class BModuleImpl implements BModuleApi{ @Override public void testB() { System.out.println("B模块操作"); } } /** *客户端 *@Author: April */ public class Client { public static void main(String[] args) { AModuleApi moduleA=new AModuleImpl(); moduleA.testA(); BModuleApi moduleB=new BModuleImpl(); moduleB.testB(); //.... } }
这对客户端而言是个麻烦,而且一旦其中某个模块发生了变化,可能会引起客户端也要随之变化。那么如何实现,才能让子系统外部的客户端既能简单的使用这些子系统内部的模块功能,而又不用客户端去与子系统内部的多个模块交互呢?一个合理的方案就是——外观模式
定义:为子系统中一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一系统更加容易使用
结构示意图:
其实很简单,只添加一个Facade对象,然后在里面实现客户端需要的功能就可以了:
public class Facade { /** * 示例方法:满足客户需求的功能 */ public void test(){ //将实现委派给内部多个模块 AModuleApi moduleA=new AModuleImpl(); moduleA.testA(); BModuleApi moduleB=new BModuleImpl(); moduleB.testB(); //... } } public class Client { public static void main(String[] args) { //使用Facade new Facade().test(); } }
理解外观模式
-
本质:封装交互,简化调用
-
对设计原则的体现:"迪米特原则(最少知识原则)"
-
外观模式的目的不是给子系统添加新的功能接口(你可以这么做,但不建议),而是为了让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能更简单的使用子系统
-
你可能会问,这不就是把原来客户端的代码搬到Facade里了吗?有什么变化啊?其实变化就在于:
-
Facade是位于系统这边的,它就相当于屏蔽了外部客户端和系统内部模块的交互。不但方便了客户端的调用,而且封装了系统内部的细节功能。Facade与各个模块的交互过程已经属于内部实现了。
-
Facade的功能可以被多个客户端调用,也就是实现了复用。
-
-
外观提供了缺省的功能实现。外观对象可以为用户提供一个简单的、缺省的实现,这个实现对大多数用户已经足够。但 外观并不限制那些需要更多定制功能的用户,可以去访问内部模块的功能,即有外观,但是可以不用。
-
缺点:过多或不太合理的Facade容易让人迷惑。到底是调用Facade好呢还是直接调用模块好。