版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzx_longyou/article/details/51636128
2.1 场景问题
2.1.1 生活中的示例
生活中组装电脑通常有方案。第一种,是到电子市场把自己所需的配件买回来自己组装,需要对各个配件都比较属性,才能选择最合适的配件,而且要考虑配件之间兼容性。第二种,是到电子市场找一家专业的装机公司,提出具体需求,让他们帮你组装,我们只需等着拿电脑。
这个专业的装机公司就相当于“外观模式”。将上面所述的电脑配件抽象成模块,第一种方案,客户就需要对各个模块都熟悉,了解其功能才能做出选择;第二种方案,客户只需要与装机公司这个“外观模式”打交道,不需要了解各个模块的细节功能,不用跟系统各个模块交互,这样就显得更加简单了。
如何实现,才能让子系统外部的客户端在使用子系统的时候,既能简单地使用这些子系统内部的模块功能,而又不用客户端去与子系统内部的多个模块交互呢? 使用外观模式可以解决这样的问题。
2.2 解决方案
2.2.1 使用外观模式来解决问题
1. 外观模式的定义
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。这里所说的接口,并不等价于interface,主要是指外部和内部交互的一个通道,可以是类的方法,也可以是interface的方法。
2. 应用外观模式来解决问题的思路
外观模式就是引入一个外观类,在这个类里面定义客户端想要的简单的方法,然后在这些方法的实现里面,由外观类再去调用内部的多个模块来实现功能,从而让客户端变得简单,这样客户端只要和外观类交互就可以了。
2.2.2 外观模式示例代码
外观模式实例的整体结构示意图:
示例代码:
public interface AModuleApi {
/**
* A模块对外的一个功能方法
*/
public void testA();
}
public class AModuleImpl implements AModuleApi {
@Override
public void testA() {
System.out.println("现在在A模块里操作testA方法");
}
}
public interface BModuleApi {
/**
* B模块对外的一个功能方法
*/
public void testB();
}
public class BModuleImpl implements BModuleApi {
@Override
public void testB() {
System.out.println("现在在B模块里操作testB方法");
}
}
public interface CModuleApi {
/**
* C模块对外的一个功能方法
*/
public void testC();
}
public class CModuleImpl implements CModuleApi {
@Override
public void testC() {
System.out.println("现在在C模块里操作testC方法");
}
}
/**
* 外观对象
*/
public class Facade {
public void test() {
//在内部实现的时候,可能会调用到内部的多个模块
AModuleApi a = new AModuleImpl();
a.testA();
BModuleApi b = new BModuleImpl();
b.testB();
CModuleApi c = new CModuleImpl();
c.testC();
}
}
public class Clinet {
public static void main(String[] args) {
new Facade().test();
}
}
2.3 模式讲解
2.3.1 认识外观模式
1. 外观模式的目的
外观模式的目的不是给子系统添加新的功能接口,而是为了让外部减少与子系统内部多个模块的交互,松散耦合,从而让外部能够更简单地使用子系统。
2. 使用外观和不使用外观相比有何变化
表面上看就是把客户端的代码搬到Facade里面了,但实质是发生了变化。Facade位于A、B、C模块组成的系统这边,而不是位于客户端。因此,它相当于屏蔽了外部客户端和系统内部模块的交互,从而把A、B、C模块组合成一个整体对外,不但方便了客户端的调用,而且封装了系统内部的细节功能。如果今后调用模块的算法发生了变化,只需要修改Facade的实现就可以了。
另一个优点是,Facade的功能被多个客户端调用,实现了功能的共享,实现了复用。
2.3.2 外观模式的优缺点
1. 松散耦合:外观模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。
2. 简单易用:外观模式让子系统更加易用,客户端不在需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟外观交互就可以。
3. 更好地划分访问的层次:有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到外观中,这样既方便客户端使用,也很好的隐藏了内部细节。
2.3.3 思考外观模式
1. 外观模式的本质:封装交互,简化调用
2. 对设计原则的体现:最少知识原则。
如果不使用外观模式,客户端通常需要和子系统内部的多个模块交互,于是客户端和这些模块就有依赖关系,任意一个模块的变动都会引起客户端的变动。
使用外观模式后,客户端只需要和外观类交互,客户端不需要关心子系统内部模块的变动情况,客户端只是和这个外观类有依赖关系。可以在不影响客户端的情况下,实现系统内部的维护和扩展。
3. 何时选择外观模式
如果希望为一个复杂的子系统提供一个简单的接口,可以考虑使用外观模式。使用外观对象来实现大部分客户需要的功能,从而简化客户的使用。
如果想要让客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式。使用外观对象来讲这个子系统与它的客户分开,从而提供子系统的独立性和可移植性。
如果构建多层结构系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样可以简化层间调用,也可以松散层次之间的依赖关系。