什么是外观设计模式?

200

Facade是包含许多其他类的类吗?

是什么使它成为一种设计模式?对我来说,它就像一个普通的类。

你能向我解释一下这个Facade模式吗?


8
每个设计模式在实现中都是一组类。 - Felix Kling
1
外观模式通过将多个接口隐藏在一个类中来创建易于使用的界面。此文章有更多细节 - user3199690
这篇文章 https://programmerzdojo.com/java-tutorials/facade-design-pattern-in-java-with-examples/ 很好地解释了外观设计模式在Java中的应用。 - rishi007bansod
我不得不给这个点个踩,因为它“没有展示研究努力”。 - Roy Truelove
1
@RoyTruelove,你想做什么就做什么。只要有支持性的答案回答问题,就不在乎了。有任何支持性的答案回答这个问题吗? - kevin
20个回答

199

设计模式是解决重复性问题的一种常见方法。在所有设计模式中,类都只是普通类。重要的是它们的结构以及如何相互协作以最佳方式解决给定问题。

外观设计模式简化了复杂系统的接口,因为它通常由组成复杂系统子系统的所有类组成。

外观模式保护用户免受系统复杂细节的干扰,并向用户提供易于使用简化视图。它还将使用系统的代码与子系统的详细信息解耦,使得以后修改系统更容易。

http://www.dofactory.com/Patterns/PatternFacade.aspx

http://www.blackwasp.co.uk/Facade.aspx

此外,在学习设计模式时,重要的是要能够识别哪种模式适用于您的特定问题,然后恰当地使用它。误用模式或者仅仅因为了解而试图将其适用于某些问题是很常见的错误。在学习和使用设计模式时要注意这些陷阱。


11
@kevin:知道何时使用它们是最困难的部分。理论上,模式可能很容易,但在实践中它们是困难的(imo)。你只能通过经验来学习,即编码、编码、编码。 - Felix Kling
外观设计模式通常用于隐藏详细类的实现并安全地提供公共 API。 - yebw
33
在 jQuery 中,$ 只是门面设计模式的简单示例,它提供了简单的接口并隐藏了所有复杂性。 - Ajay Beniwal
如果有人正在寻找一个带有现实世界例子的外观设计模式,我发现了这个简短的YouTube教程。希望它有用。https://youtu.be/dLjJo2v2re8 - Sankar ganesh
当应用程序变得更大时,我们可以为单个系统拥有多个门面层吗? - Jeeva J
这会使对象相互依赖吗?这是否违反了 DI 设计模式? - AminM

106

维基百科提供了一个很好的外观模式示例。

/* Complex parts */

class CPU {
    public void freeze() { ... }
    public void jump(long position) { ... }
    public void execute() { ... }
}

class Memory {
    public void load(long position, byte[] data) { ... }
}

class HardDrive {
    public byte[] read(long lba, int size) { ... }
}

/* Facade */

class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDrive hd;

    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDrive();
    }

    public void start() {
        processor.freeze();
        ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
        processor.jump(BOOT_ADDRESS);
        processor.execute();
    }
}

/* Client */

class You {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

7
这是一个很好的例子。如果客户选择这样做,他们需要能够拼凑出外立面的所有步骤,没有任何私有方法应该被隐藏。 - Rob
2
在我看来,这不是一个好的例子,因为它没有强调用途。这个例子只是展示了一个常规类,就像TO说的一样。与硬件的关联是组合关系。也许对于维基上的例子来说有些过度设计,但使用依赖注入而不是实例化子模块会强调意图,并可能避免TO的混淆。 - ManuelSchneid3r
这是一个惊人的例子,它将成千上万的单词简化为理解概念本身的要点。其余的只是围绕不同场景可能出现的细节(当然,设计模式永远无法涵盖每种情况)。 - Syed

44

正如前面的回答所解释的那样,它提供了一个简单的接口给消费者使用。

例如:"观看ESPN"是预期的功能。但它涉及到几个步骤,如下:

  1. 如有必要,打开电视;
  2. 检查卫星/有线电视是否正常;
  3. 如果需要,切换到ESPN频道。

但是外观模式将简化这个过程,只向客户端提供“观看ESPN”的功能。


31

外观模式隐藏了系统的复杂性,并提供了一个接口给客户端,客户端可以通过该接口访问系统。

public class Inventory {
public String checkInventory(String OrderId) {
    return "Inventory checked";
}
}

public class Payment {
public String deductPayment(String orderID) {
    return "Payment deducted successfully";
}
}


public class OrderFacade {
private Payment pymt = new Payment();
private Inventory inventry = new Inventory();

public void placeOrder(String orderId) {
    String step1 = inventry.checkInventory(orderId);
    String step2 = pymt.deductPayment(orderId);
    System.out
            .println("Following steps completed:" + step1
                    + " & " + step2);
   }
}

public class Client {
       public static void main(String args[]){
         OrderFacade orderFacade = new OrderFacade();
         orderFacade.placeOrder("OR123456");
         System.out.println("Order processing completed");
       }
  }

在不经过“OrderFacade”的情况下,子系统之间是否允许相互通信?例如,在您的示例中,“Payment”和“Inventory”之间是否可以直接通信? - Isuru

23

一个简短而简单的解释:

  • 外观模式为子系统中一组接口提供了一个统一的接口。
  • 外观定义了一个更高级别的接口,使子系统更容易使用。

尝试理解有和没有Facade的情况:
如果您想将资金从账户1转移到账户2,则需要调用两个子系统:从账户1提取和向账户2存款。

有和没有外观


简单明了的解释和示例,谢谢!您能否解释一下什么是子系统?当子系统可能由相对无关的子类/函数组成时,您的定义适用于几乎任何类。子系统的类必须非常紧密相关,例如形成一个模块或库,以便将其称为Facade吗? - Benni
@Benni 是的,子系统(它将是一个类)可能包含相对无关的函数,但外观是一个类,在其中您可以决定调用哪些特定函数。您想预订“旅游套餐”,您在一个地方/表单中选择酒店、出租车、航班,然后内部外观调用不同适当类的函数并向您返回最终结果。是这样吗? - Arun Raaj

11

外观模式不应该被描述为一个包含许多其他类的类。它实际上是这些类的接口,应该使得这些类更容易使用,否则外观模式将毫无用处。


9

关于您的问题:

Facade是包含许多其他类的类吗?

是的。它是应用程序中许多子系统的包装器。

什么使它成为设计模式?对我来说,它就像一个普通的类

所有设计模式都是普通的类。@Unmesh Kondolikar正确回答了这个问题。

你能给我解释一下这个Facade吗?我对设计模式很新。

根据GoF,Facade设计模式被定义为:

为子系统中的一组接口提供统一的接口。Facade模式定义了一个更高级别的接口,使子系统更易于使用

Facade模式通常在以下情况下使用:

  1. 需要简单的接口来访问复杂的系统。
  2. 需要每个分层软件级别的入口点。

让我们以cleartrip网站为例。

该网站提供预订选项。

  1. 机票
  2. 酒店
  3. 机+酒套餐

代码片段:

import java.util.*;

public class TravelFacade{
    FlightBooking flightBooking;
    TrainBooking trainBooking;
    HotelBooking hotelBooking;

    enum BookingType {
        Flight,Train,Hotel,Flight_And_Hotel,Train_And_Hotel;
    }; 
    
    public TravelFacade(){
        flightBooking = new FlightBooking();
        trainBooking = new TrainBooking();
        hotelBooking = new HotelBooking();        
    }
    public void book(BookingType type, BookingInfo info){
        switch(type){
            case Flight:
                // book flight;
                flightBooking.bookFlight(info);
                return;
            case Hotel:
                // book hotel;
                hotelBooking.bookHotel(info);
                return;
            case Train:
                // book Train;
                trainBooking.bookTrain(info);
                return;
            case Flight_And_Hotel:
                // book Flight and Hotel
                flightBooking.bookFlight(info);
                hotelBooking.bookHotel(info);
                return;
             case Train_And_Hotel:
                // book Train and Hotel
                trainBooking.bookTrain(info);
                hotelBooking.bookHotel(info);
                return;                
        }
    }
}
class BookingInfo{
    String source;
    String destination;
    Date    fromDate;
    Date     toDate;
    List<PersonInfo> list;
}
class PersonInfo{
    String name;
    int       age;
    Address address;
}
class Address{

}
class FlightBooking{
    public FlightBooking(){
    
    }
    public void bookFlight(BookingInfo info){
    
    }
}
class HotelBooking{
    public HotelBooking(){
    
    }
    public void bookHotel(BookingInfo info){
    
    }
}
class TrainBooking{
    public TrainBooking(){
    
    }
    public void bookTrain(BookingInfo info){
    
    }
}

解释:

  1. FlightBookingTrainBookingHotelBooking是大型系统TravelFacade的不同子系统。

  2. TravelFacade提供了一个简单的接口,以预订以下选项之一:

    机票预订
    火车票预订
    酒店预订
    机票+酒店预订
    火车票+酒店预订
    
  3. 来自TravelFacade的预订API内部调用子系统的以下API:

    flightBooking.bookFlight
    trainBooking.bookTrain(info);
    hotelBooking.bookHotel(info);
    
  4. 这样,TravelFacade提供了更简单、更易于使用的API,而不会暴露子系统的API。


6

有一个非常好的现实生活中的例子展示了这个模式 - 汽车启动器引擎

作为司机,我们只需打开钥匙,汽车就能启动。如此简单。幕后,许多其他汽车系统参与其中(如电池、发动机、燃料等),以确保汽车成功启动,但它们隐藏在启动器背后。

正如您所看到的,汽车启动器是Facade。它为我们提供易于使用的接口,而不必担心所有其他汽车系统的复杂性。

让我们总结一下:

外观模式简化并隐藏了大型代码块或API的复杂性,提供了更清洁、易于理解和易于使用的接口。


6
外观模式是许多其他接口的包装器,以产生一个更简单的接口。
设计模式很有用,因为它们解决了经常出现的问题,并且通常简化了代码。在开发人员团队中,如果他们同意使用相同的模式,那么在维护彼此的代码时,它提高了效率和理解能力。
尝试阅读更多的模式:
外观模式:http://www.dofactory.com/Patterns/PatternFacade.aspx#_self1 或者更一般地说:http://www.dofactory.com/Patterns/Patterns.aspx

我在这里尝试用房屋贷款验证流程的例子来描述Facade设计模式。 - Nilesh Gule

6
一个额外的Facade模式的应用是降低团队的学习曲线。让我举个例子:
假设你的应用程序需要使用Excel的COM对象模型与MS Excel进行交互。你的一个团队成员知道所有的Excel API,并在其上创建了一个Facade,满足应用程序的所有基本场景。团队中的其他成员无需花费时间学习Excel API。团队可以在不知道内部或涉及完成场景的所有MS Excel对象的情况下使用facade。这不是很棒吗?
因此,它为复杂的子系统提供了简化和统一的接口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接