介绍

  1. 外观模式(Facade),也叫“过程模式:外观模式为子系统中的一组接口提供一个一致的界面(java中的各个方法),此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
  2. 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节

原理image-20201009112502754.png

原理类图的说明(外观模式的角色)

  1. 外观类(Facade): 为调用端提供统一的调用接口, 外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象
  2. 调用者(Client): 外观接口的调用者
  3. 子系统的集合:指模块或者子系统,处理Facade 对象指派的任务,他是功能的实际提供者

案例
组建一个家庭影院:
DVD播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,其过程为:
• 直接用遥控器:统筹各设备开关
• 开爆米花机
• 放下屏幕
• 开投影仪
• 开音响
• 开DVD,选dvd
• 去拿爆米花
• 调暗灯光
• 播放
• 观影结束后,关闭各种设备

  1. //各种设备
  2. public class DVDPlayer {
  3. private static DVDPlayer instance = new DVDPlayer();
  4. public static DVDPlayer getInstanc() {
  5. return instance;
  6. }
  7. public void on() {
  8. System.out.println(" dvd on ");
  9. }
  10. public void off() {
  11. System.out.println(" dvd off ");
  12. }
  13. public void play() {
  14. System.out.println(" dvd is playing ");
  15. }
  16. //....
  17. public void pause() {
  18. System.out.println(" dvd pause ..");
  19. }
  20. }
  21. public class Popcorn {
  22. private static Popcorn instance = new Popcorn();
  23. public static Popcorn getInstance() {
  24. return instance;
  25. }
  26. public void on() {
  27. System.out.println(" popcorn on ");
  28. }
  29. public void off() {
  30. System.out.println(" popcorn ff ");
  31. }
  32. public void pop() {
  33. System.out.println(" popcorn is poping ");
  34. }
  35. }
  36. public class Projector {
  37. private static Projector instance = new Projector();
  38. public static Projector getInstance() {
  39. return instance;
  40. }
  41. public void on() {
  42. System.out.println(" Projector on ");
  43. }
  44. public void off() {
  45. System.out.println(" Projector ff ");
  46. }
  47. public void focus() {
  48. System.out.println(" Projector is Projector ");
  49. }
  50. //...
  51. }
  52. public class Screen {
  53. private static Screen instance = new Screen();
  54. public static Screen getInstance() {
  55. return instance;
  56. }
  57. public void up() {
  58. System.out.println(" Screen up ");
  59. }
  60. public void down() {
  61. System.out.println(" Screen down ");
  62. }
  63. }
  64. public class Stereo {
  65. private static Stereo instance = new Stereo();
  66. public static Stereo getInstance() {
  67. return instance;
  68. }
  69. public void on() {
  70. System.out.println(" Stereo on ");
  71. }
  72. public void off() {
  73. System.out.println(" Screen off ");
  74. }
  75. public void up() {
  76. System.out.println(" Screen up.. ");
  77. }
  78. }
  79. public class TheaterLight {
  80. private static TheaterLight instance = new TheaterLight();
  81. public static TheaterLight getInstance() {
  82. return instance;
  83. }
  84. public void on() {
  85. System.out.println(" TheaterLight on ");
  86. }
  87. public void off() {
  88. System.out.println(" TheaterLight off ");
  89. }
  90. public void dim() {
  91. System.out.println(" TheaterLight dim.. ");
  92. }
  93. public void bright() {
  94. System.out.println(" TheaterLight bright.. ");
  95. }
  96. }
  1. //外观类(面向调用者的类)
  2. public class HomeTheaterFacade {
  3. //定义各个子系统对象
  4. private TheaterLight theaterLight;
  5. private Popcorn popcorn;
  6. private Stereo stereo;
  7. private Projector projector;
  8. private Screen screen;
  9. private DVDPlayer dVDPlayer;
  10. //构造器
  11. public HomeTheaterFacade() {
  12. super();
  13. this.theaterLight = TheaterLight.getInstance();
  14. this.popcorn = Popcorn.getInstance();
  15. this.stereo = Stereo.getInstance();
  16. this.projector = Projector.getInstance();
  17. this.screen = Screen.getInstance();
  18. this.dVDPlayer = DVDPlayer.getInstanc();
  19. }
  20. //操作分成 4 步
  21. public void ready() {
  22. popcorn.on();
  23. popcorn.pop();
  24. screen.down();
  25. projector.on();
  26. stereo.on();
  27. dVDPlayer.on();
  28. theaterLight.dim();
  29. }
  30. public void play() {
  31. dVDPlayer.play();
  32. }
  33. public void pause() {
  34. dVDPlayer.pause();
  35. }
  36. public void end() {
  37. popcorn.off();
  38. theaterLight.bright();
  39. screen.up();
  40. projector.off();
  41. stereo.off();
  42. dVDPlayer.off();
  43. }
  44. }
  1. //用户只调用外观类就可以控制家庭影院的所有设备
  2. public class Client {
  3. public static void main(String[] args) {
  4. //这里直接调用。。 很麻烦
  5. HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
  6. homeTheaterFacade.ready();
  7. homeTheaterFacade.play();
  8. homeTheaterFacade.end();
  9. }
  10. }

外观模式的注意事项和细节

  1. 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
  2. 外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展
  3. 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
  4. 当系统需要进行分层设计时,可以考虑使用Facade模式
  5. 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰简单的接口, 让新系统与Facade类交互,提高复用性
  6. 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维护为目的。