[关闭]
@w1992wishes 2018-03-13T14:38:29.000000Z 字数 4586 阅读 977

设计模式--外观模式

设计模式 结构型模式


目录

本文的结构如下:

一、前言

话说某天空气质量回到秦汉,月色如水倾泻,温度适宜,微风袭人,我在院子树下架起圆木桌,摆上雕花凳,桌上依次摆放红烧肘子,烧牛肉,剁椒鱼头,烤羊排,炸猛男......美人在怀,饮一口小酒,复又夹起一块牛肉放入口中,这滋味,岂不快哉?

快你个头啊,赶紧起来给我码代码。

恍惚中听到一声怒吼,我从好梦中惊醒。啊,没有酒,没有肉,没有美人,只有汉城4点钟的太阳,油腻的中年组长大叔和屏幕前没有吃完的老坛酸菜面,泪哭。

咳咳,回到正题,我们接着讲美食。美食适合享用,不宜动手操弄,如果自己动手,要做好一道美食,需要的事物很多,碗,锅,水,调味品,食材等等,需要这些东西经过一些列交互才能得到最后的美食。

美食做法实在太过累人,可是还是想吃怎么办呢?

找妈妈啊,一句:“妈,我想吃肉。”然后可以逛知乎,刷微博,打游戏,在手机上进行了一轮复杂操作,就听妈妈喊一声:“吃饭了。”于是乎,一只手握着手机改看小说,一只手夹肉,嘴里嘟囔道:“妈,你做的红烧肉太好吃了。”

咳咳,这次真的回到正题。

刚才“饿了找妈妈”的例子其实就是在说外观模式。在软件开发中,有时候某个客户类(“我”)可能会与多个业务类(“水,调味品,食材”)交互,而这些需要交互的业务类经常会作为一个整体出现,由于涉及到的类比较多,导致使用时代码较为复杂,此时,特别需要一个类似“妈妈”一样的角色,由它来负责和多个业务类进行交互,而客户类只需与该类交互。外观模式通过引入一个新的外观类(Facade)来实现该功能,外观类充当了软件系统中的“妈妈”,它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互。在外观模式中,那些需要交互的业务类被称为子系统(Subsystem)。如果没有外观类,那么每个客户类需要和多个子系统之间进行复杂的交互,系统的耦合度将很大,而引入外观类之后,客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度。

插一句,不得不说,妈妈其实就像个服务员,不停服务自己的丈夫和孩子,还经常受到埋怨,太辛苦了。

二、什么是外观模式

为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

外观模式又称为门面模式,它是一种对象结构型模式。外观模式是迪米特法则的一种具体实现,通过引入一个新的外观角色可以降低原有系统的复杂度,同时降低客户类与子系统的耦合度。

三、模式的结构

外观模式包含如下两个角色:

外观模式中所指的子系统是一个广义的概念,它可以是一个类、一个功能模块、系统的一个组成部分或者一个完整的系统。子系统类通常是一些业务类,实现了一些具体的、独立的业务功能,其典型代码:

  1. class SubSystemA
  2. {
  3. public void MethodA()
  4. {
  5. //业务实现代码
  6. }
  7. }
  8. class SubSystemB
  9. {
  10. public void MethodB()
  11. {
  12. //业务实现代码
  13. }
  14. }
  15. class SubSystemC
  16. {
  17. public void MethodC()
  18. {
  19. //业务实现代码
  20. }
  21. }

在引入外观类之后,与子系统业务类之间的交互统一由外观类来完成,在外观类中通常存在如下代码:

  1. class Facade
  2. {
  3. private SubSystemA obj1 = new SubSystemA();
  4. private SubSystemB obj2 = new SubSystemB();
  5. private SubSystemC obj3 = new SubSystemC();
  6. public void Method()
  7. {
  8. obj1.MethodA();
  9. obj2.MethodB();
  10. obj3.MethodC();
  11. }
  12. }

由于在外观类中维持了对子系统对象的引用,客户端可以通过外观类来间接调用子系统对象的业务方法,而无须与子系统对象直接交互。引入外观类后,客户端代码变得非常简单,典型代码:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. Facade facade = new Facade();
  6. facade.Method();
  7. }
  8. }

四、代码示例

4.1、就以“饿了找妈妈”为例,在不使用外观模式前,是这样设计的:

  1. /**
  2. * Created by w1992wishes on 2017/11/9.
  3. */
  4. public class Material {
  5. public void prepare(){
  6. System.out.println("从菜市场买回食材,并清洗");
  7. }
  8. }
  9. /**
  10. * Created by w1992wishes on 2017/11/9.
  11. */
  12. public class Pan {
  13. public void wash(){
  14. System.out.println("炒菜前要先洗锅");
  15. }
  16. }
  17. /**
  18. * Created by w1992wishes on 2017/11/9.
  19. */
  20. public class Flavouring {
  21. public void add(){
  22. System.out.println("依次放入各种调味品");
  23. }
  24. }

我进行制作美食:

  1. /**
  2. * Created by w1992wishes on 2017/11/9.
  3. */
  4. public class Client {
  5. public static void main(String[] args) {
  6. Material material = new Material();
  7. Pan pan = new Pan();
  8. Flavouring flavouring = new Flavouring();
  9. System.out.println("肚子饿了");
  10. material.prepare();
  11. pan.wash();
  12. flavouring.add();
  13. System.out.println("出锅,可以吃饭了");
  14. }
  15. }

结果:
肚子饿了
从菜市场买回食材,并清洗
炒菜前要先洗锅
依次放入各种调味品
出锅,可以吃饭了

4.2、使用外观模式

  1. /**
  2. * Created by w1992wishes on 2017/11/9.
  3. */
  4. public class Mom {
  5. Material material;
  6. Pan pan;
  7. Flavouring flavouring;
  8. public Mom(){
  9. this.material = new Material();
  10. this.pan = pan = new Pan();
  11. this.flavouring = new Flavouring();
  12. }
  13. public void makeDish(){
  14. material.prepare();
  15. pan.wash();
  16. flavouring.add();
  17. }
  18. }

妈妈制作美食:

  1. public class Client {
  2. public static void main(String[] args) {
  3. Mom mom = new Mom();
  4. System.out.println("肚子饿了");
  5. mom.makeDish();
  6. System.out.println("出锅,可以吃饭了");
  7. }
  8. }

五、优点和缺点

5.1、优点

5.2、缺点

六、适用环境

在以下情况下可以使用外观模式:

七、模式应用

八、模式扩展

九、补充--与适配器模式的区别

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注