daily 2017 7 18 设计模式之门面模式 - wtdig/study GitHub Wiki

门面模式

使用场景:

门面模式(Facade):为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 适用场景:

1、为一个复杂子系统提供一个简单接口时,由于子系统往往因为不断演化而变得越来越复杂,但这种变化不应该影响到客户的调用,此时使用 Facade 模式对外提供一个访问的接口;此外,还可以提供多个 Facade 类以实现不同的子系统的定制;

2、客户与抽象类的实现部分之间存在着很大的依赖性。用 Facade 模式将这个子系统与客户以及其他的子系统分离解耦,让客户通过 Facade 类来访问具体子系统,这样也能够保持各个子系统的独立性,即可重用;

3、构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过 Facade 进行通讯,从而简化了它们之间的依赖关系。

Facade 模式类比邮局的业务流程: 看着上面的类图,实在很简单,很难想象到底是怎么回事,就用一个生活中的具体例子来描述一下吧。平时我们寄信,都是写好正文装在信封中就投给邮局了,具体邮局是怎么完成业务的,我们作为服务的消费者并不知情,这就是一个类似的 Facade 模式,邮局对于我们消费者则是 Facade 门面。 假如邮局在其业务流程中需要增加一道特殊工序,那么在其内部只需要添加这一具体业务则可,用户并不知情。例如邮局推出给邮递员完成送信之后立刻给收信人送上一张节日贺卡的人性化服务(多好啊)。送信人可以在寄信时并不了解这一特殊服务,但信还是照样寄出去了,收信人也收到了,一个完整的工作流程就结束了。 注意:在以上例子中,一张张数据库表、一项项邮局推出的人性化服务都应该看作类图中的 Subsystem 子系统,它们是真正处理业务逻辑的对象,而不是由 Facade 来担任这一职责。 好吧,用代码实现一下: // 子系统01,邮局接收信件的业务 class Subsystem01 { public void receiveLetters() { System.out.println("邮局接收用户的信件..."); } }

// 子系统02,邮局检查信件并分类的业务 class Subsystem02 { public void checkLetters() { System.out.println("邮局检查用户的信件..."); } }

// 子系统03,邮局让邮递员送信给收信人 class Subsystem03 { public void sendToReceiver() { System.out.println("邮递员送信 ..."); } }

// 子系统04,邮局新推出的赠送贺卡的特殊业务 class Subsystem04 { public void sendGreetingCard() { System.out.println("邮局的额外送贺卡服务 ..."); } }

// Facade01 ,只是普通的送信 class Facade01 { private Subsystem01 subsystem01; private Subsystem02 subsystem02; private Subsystem03 subsystem03;

public Facade01() { 
    this.subsystem01 = new Subsystem01(); 
    this.subsystem02 = new Subsystem02(); 
    this.subsystem03 = new Subsystem03(); 
} 
 
// 普通的送信,委托给各个必要的子系统 
public void commonSendLetters() { 
    this.subsystem01.receiveLetters(); 
    this.subsystem02.checkLetters(); 
    this.subsystem03.sendToReceiver(); 
}    

}

//Facade02 ,增加了送贺卡的业务 class Facade02 {

// 委托 Facade01 进行普通业务的处理 
private Facade01 facade01; 
private Subsystem04 subsystem04; 
 
public Facade02() { 
    this.facade01 = new Facade01(); 
    this.subsystem04 = new Subsystem04(); 
} 
 
// 特殊的送信 
public void specialSendLetters() { 
    this.facade01.commonSendLetters(); 
    // 普通的送信之后再赠送贺卡 
    this.subsystem04.sendGreetingCard(); 
} 

}

// 测试类,即客户寄信 public class Client { public static void main(String[] args) { Facade01 facade01 = new Facade01(); facade01.commonSendLetters();

    System.out.println(); 
     
    Facade02 facade02 = new Facade02(); 
    facade02.specialSendLetters(); 
} 

}

邮局接收用户的信件... 邮局检查用户的信件... 邮递员送信 ...

邮局接收用户的信件... 邮局检查用户的信件... 邮递员送信 ... 邮局的额外送贺卡服务 ... 在上面的邮局业务模拟中,我们在 Facade02 类中将邮局的普通业务委托给 Facade01 对象,然后才添加特殊的赠送贺卡服务,这就说明了不仅各个 Subsystem 类是可重用的,连 Facade 门面类也可以适当地进行重用,只要符合业务逻辑即可。这个重用也是委托,使得我们省去重新写相同代码的麻烦。

那么在这里我们可以扩展一下,如果一个 Subsystem 类中的业务功能太过庞大,那么我们可以设计多个 Facade 类,每一个都内置该 Subsystem 类中的某些业务,即拆分 Subsystem ,再提供一个 Facade 类来封装这些拆分出来的 Facade 类。

邮局再有什么特殊业务,扩展具体的 Subsystem 类即可,但是,这样的话就需要对原来的 Facade 进行修改了,或者再提供另一个 Facade 类,就像上面的 Facade02 类。

基本上,在 Facade 模式的通用类图中没有体现出 抽象,而我们的简单实现中也是如此。我认为,这是因为 Facade 模式旨在对客户提供一个访问入口、接口,具体内部的 Subsystem 子系统是否遵循了 抽象 的编程方法,这没有关系,只要客户是通过 Facade 来访问、获得 Subsystem 的功能、服务即可。

⚠️ **GitHub.com Fallback** ⚠️