什么是立面设计模式?

Posted

技术标签:

【中文标题】什么是立面设计模式?【英文标题】:What is the facade design pattern? 【发布时间】:2011-07-11 16:13:16 【问题描述】:

facade 是一个包含很多其他类的类吗?

是什么让它成为一种设计模式?对我来说,这就像一堂普通的课。

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

【问题讨论】:

每个设计模式在其实现中都有一堆类。 外观模式通过在一个类中隐藏多个接口来创建一个易于使用的接口。 This article has more details. 在这篇文章中有很好的解释programmerzdojo.com/java-tutorials/… 不得不放弃这个,因为它“没有显示出研究成果” @RoyTruelove,做你想做的。只要这个问题有支持性的答案,就不会在意。对这个问题有任何支持性的答案吗? 【参考方案1】:

设计模式是解决反复出现的问题的常用方法。所有设计模式中的类都是普通类。重要的是它们的结构以及它们如何协同工作以最佳方式解决给定问题。

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

Facade 使用户免受系统复杂细节的影响,并为他们提供simplified view,即easy to use。还decouples从子系统的细节中使用系统的代码,方便以后修改系统。

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

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

此外,在学习设计模式时,重要的是能够识别哪种模式适合您的给定问题,然后适当地使用它。仅仅因为你知道它而滥用模式或试图将其适应某个问题是很常见的事情。在学习\使用设计模式时要注意这些陷阱。

【讨论】:

@kevin:知道何时使用它们是最困难的部分。从理论上讲,模式可能很容易,但在实践中却很难。你只能学习这是经验,即。编码,编码,编码。 外观设计模式也远离用于隐藏细节类的实现和安全地提供公共API。 jquery 中的 $ 只是外观设计模式的简单示例,它提供简单的界面并隐藏所有复杂性 对于一些正在寻找具有真实世界示例的外观设计模式的人。我遇到了这个简短的 youtube 教程。希望它有用youtu.be/dLjJo2v2re8 当应用程序变大时,我们可以为单个系统拥有多个外观层吗?【参考方案2】:

Wikipedia 有一个很好的外观模式示例。

/* 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();
    

【讨论】:

这是一个很好的例子。客户需要能够拼凑外观中的所有步骤(如果他们也选择的话),私有方法不应隐藏任何内容。 恕我直言,这不是一个很好的例子,因为它没有强调用例。正如 TO 所说,这个例子只是展示了一个普通的班级。与硬件的关联是一个组合。也许对于 wiki 上的示例来说有点过分了,但是使用依赖注入而不是实例化子模块会强调意图并可能避免 TO 的混淆。 这是一个了不起的例子,因为它只是概括了数千个单词来理解概念本身。休息只是一个人可以拥有的不同场景的细节(当然设计模式永远无法涵盖每一个场景)。【参考方案3】:

如上一个答案中所述,它为消费客户端提供了一个简单的接口。 例如:“watch ESPN”是预期的功能。但它涉及几个步骤,例如:

    根据需要打开电视; 检查卫星/有线电视功能; 如果需要,切换到 ESPN。

但外观会简化这一点,只为客户端提供“观看 ESPN”功能。

【讨论】:

【参考方案4】:

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

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进行通信?在您的示例中,介于 PaymentInventory?【参考方案5】:

简短的解释:

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

尝试理解有和没有外观的场景: 如果您想将钱从 accout1 转移到 account2,那么要调用的两个子系统是,从 account1 提款和存款到 account2。

【讨论】:

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

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

【讨论】:

【参考方案7】:

关于您的查询:

Facade 是一个包含很多其他类的类吗?

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

是什么让它成为一种设计模式?对我来说,这就像一个普通的班级

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

你能解释一下这个 Facade,我是设计模式的新手。

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

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

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

    访问复杂系统需要简单的界面。 子系统的抽象和实现是紧密耦合的。 需要每个分层软件级别的入口点。 系统非常复杂或难以理解。

我们来看一个cleartrip网站的真实单词示例。

本网站提供预订选项

    航班 酒店 航班 + 酒店

代码sn-p:

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)

    

解释:

    FlightBooking, TrainBooking and HotelBooking是大系统的不同子系统:TravelFacade

    TravelFacade 提供了一个简单的界面来预订以下选项之一

    Flight Booking
    Train Booking 
    Hotel Booking
    Flight + Hotel booking 
    Train + Hotel booking
    

    TravelFacade 的 book API 在内部调用子系统 API 的下方

    flightBooking.bookFlight
    trainBooking.bookTrain(info);
    hotelBooking.bookHotel(info);
    

    通过这种方式,TravelFacade 提供了更简单易用的 API,而无需暴露子系统 API。

关键要点:(来自journaldev Pankaj Kumar 的文章

    外观模式更像是客户端应用程序的助手 外观模式可以应用于任何开发点,通常是当接口数量增加和系统变得完整时x。 子系统接口不知道 Facade,它们不应该有任何 Facade 接口的引用 外观模式应该应用于类似类型的接口,它的目的是提供一个接口而不是多个接口来完成类似的工作

也请查看sourcemaking 文章以获得更好的理解。

【讨论】:

【参考方案8】:

外观模式是许多其他接口的包装器,以产生更简单的接口。

设计模式很有用,因为它们可以解决重复出现的问题,并且通常可以简化代码。在一个同意使用相同模式的开发人员团队中,它可以提高维护彼此代码时的效率和理解力。

尝试阅读更多模式:

外观图案:http://www.dofactory.com/Patterns/PatternFacade.aspx#_self1

或更笼统地说:http://www.dofactory.com/Patterns/Patterns.aspx

【讨论】:

nileshgule.com/2012/07/facade-design-pattern.html 我试图在这里用一个房屋贷款验证过程的例子来描述外观设计模式。【参考方案9】:

外观模式的另一个用途可能是减少团队的学习曲线。举个例子吧:

让我们假设您的应用程序需要利用 Excel 提供的 COM 对象模型与 MS Excel 进行交互。您的一位团队成员了解所有 Excel API,他在其之上创建了一个 Facade,它满足了应用程序的所有基本场景。团队中的其他成员无需花时间学习 Excel API。团队可以在不了解实现场景的内部结构或所有 MS Excel 对象的情况下使用外观。是不是很棒?

因此,它在复杂的子系统之上提供了一个简化和统一的界面。

【讨论】:

【参考方案10】:

有一个很好的现实生活示例  - 汽车启动引擎

作为司机,我们只需打开钥匙,汽车就可以启动。尽可能简单。在幕后,涉及到许多其他汽车系统(如电池、发动机、燃料等),以使汽车能够成功启动,但它们隐藏在启动器后面。

如您所见,汽车启动器是 Facade。它为我们提供了易于使用的界面,而无需担心所有其他汽车系统的复杂性。

让我们总结一下:

Facade 模式简化并隐藏了大型代码块或 API 的复杂性,提供更简洁、易于理解且易于使用的界面。

【讨论】:

【参考方案11】:

外观的另一个例子: 假设您的应用程序连接到数据库并在 UI 上显示结果。您可以使用外观使您的应用程序可配置,如使用数据库或模拟对象运行。因此,您将对外观类进行所有数据库调用,它将读取应用程序配置并决定触发数据库查询或返回模拟对象。这种方式应用程序变得独立于数据库,以防数据库不可用。

【讨论】:

【参考方案12】:

外观暴露了大部分被调用的简化函数,而实现隐藏了客户端必须处理的复杂性。通常,该实现使用多个包、类和函数。编写良好的外观使得直接访问其他类很少见。例如,当我访问 ATM 并提取一些金额时。 ATM 隐藏了它是直接进入自有银行,还是通过协商网络为外部银行提供服务。 ATM 就像一个门面,消耗多个设备和子系统,作为客户端,我不必直接处理这些设备和子系统。

【讨论】:

【参考方案13】:

外观是一个具有一定功能级别的类,位于工具包和完整的应用程序之间,提供包或子系统中类的简化用法。 Facade 模式的目的是提供一个使子系统易于使用的接口。 -- 摘自book C# 中的设计模式。

【讨论】:

【参考方案14】:

Facade 讨论了将复杂的子系统封装在单个接口对象中。这减少了成功利用子系统所需的学习曲线。它还促进了子系统与其潜在的许多客户的分离。另一方面,如果 Facade 是子系统的唯一接入点,它将限制“高级用户”可能需要的功能和灵活性。

来源:https://sourcemaking.com/design_patterns/facade

【讨论】:

【参考方案15】:

设计模式是软件设计中给定上下文中常见问题的通用可重用解决方案。

外观设计模式是一种结构模式,因为它定义了一种在类或实体之间创建关系的方式。外观设计模式用于定义更复杂子系统的简化接口。

外观模式在处理大量相互依赖的类或需要使用多种方法的类时是理想的,尤其是当它们使用复杂或难以理解时。外观类是一个“包装器”,其中包含一组易于理解且易于使用的成员。这些成员代表外观用户访问子系统,隐藏实现细节。

外观设计模式在包装设计不佳但由于源代码不可用或现有接口被广泛使用而无法重构的子系统时特别有用。有时您可能决定实现多个外观来为不同目的提供功能子集。

外观模式的一个示例用途是将网站与业务应用程序集成。现有软件可能包含大量必须以特定方式访问的业务逻辑。该网站可能只需要对该业务逻辑的有限访问。例如,网站可能需要显示待售物品是否已达到有限的库存水平。外观类的 IsLowStock 方法可以返回一个布尔值来指示这一点。在幕后,这种方法可能隐藏了处理当前实物库存、进货库存、分配项目和每个项目的低库存水平的复杂性。

【讨论】:

【参考方案16】:

它只是创建一个包装器来调用多个方法。 你有一个A 类,其方法为x()y()B 类,其方法为k()z()。 你想一次调用 x, y, z ,使用 Facade 模式来做到这一点,你只需创建一个 Facade 类并创建一个方法,比如说xyz()。 无需单独调用每个方法(x、y 和 z),您只需调用调用这些方法的外观类的包装方法 (xyz())。

类似的模式是存储库,但主要用于数据访问层。

【讨论】:

【参考方案17】:

所有设计模式都是以某种方式排列的适合特定应用程序的一些类。外观模式的目的是隐藏一个或多个操作的复杂性。你可以从http://preciselyconcise.com/design_patterns/facade.php看一个例子并学习门面模式

【讨论】:

【参考方案18】:

我喜欢Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates - Head First Design Patterns 书中的一个例子。 例子: 假设您创建了家庭影院,最后您想看电影。所以你必须这样做:

        Amplifier amplifier = new Amplifier();
        CdPlayer cdPlayer = new CdPlayer();
        DvdPlayer dvdPlayer = new DvdPlayer();
        Lights lights = new Lights();
        PopcornPopper popcornPopper = new PopcornPopper();
        Projector projector = new Projector();
        Screen screen = new Screen();

        popcornPopper.turnOn();
        popcornPopper.pop();
        amplifier.turnOn();
        amplifier.setVolume(10);
        lights.turnOn();
        lights.dim(10);
        screen.up();
        dvdPlayer.turnOn();
        dvdPlayer.play();

电影结束后会发生什么?你必须做同样的事情,但顺序相反,所以观看和结束电影的复杂性变得非常复杂。外观模式说你可以创建一个外观并让用户只调用一个方法而不是调用所有这些。 让我们创建门面:

public class HomeTheatherFacade 
    Amplifier amplifier;
    DvdPlayer dvdPlayer;
    CdPlayer cdPlayer;
    Projector projector;
    Lights lights;
    Screen screen;
    PopcornPopper popcornPopper;

    public HomeTheatherFacade(Amplifier amplifier, DvdPlayer dvdPlayer, CdPlayer cdPlayer, Projector projector, Lights lights, Screen screen, PopcornPopper popcornPopper) 
    this.amplifier = amplifier;
    this.dvdPlayer = dvdPlayer;
    this.cdPlayer = cdPlayer;
    this.projector = projector;
    this.lights = lights;
    this.screen = screen;
    this.popcornPopper = popcornPopper;


public void watchMovie(String movieTitle) 
    popcornPopper.turnOn();
    popcornPopper.pop();
    amplifier.turnOn();
    amplifier.setVolume(10);
    lights.turnOn();
    lights.dim(10);
    screen.up();
    dvdPlayer.turnOn();
    dvdPlayer.play();


public void endMovie() 
    dvdPlayer.turnOff();
    screen.down();
    lights.turnOff();
    amplifier.turnOff();


现在您可以调用 watchMovieendMovie 方法,而不是调用所有这些方法:

public class HomeTheatherFacadeTest 
    public static void main(String[] args)
        Amplifier amplifier = new Amplifier();
        CdPlayer cdPlayer = new CdPlayer();
        DvdPlayer dvdPlayer = new DvdPlayer();
        Lights lights = new Lights();
        PopcornPopper popcornPopper = new PopcornPopper();
        Projector projector = new Projector();
        Screen screen = new Screen();
        
        HomeTheatherFacade homeTheatherFacade = new HomeTheatherFacade(amplifier, dvdPlayer, cdPlayer, projector, lights, screen, popcornPopper);
        homeTheatherFacade.watchMovie("Home Alone");
        homeTheatherFacade.endMovie();
    

所以:

“外观模式为一组 子系统中的接口。 Facade 定义了一个更高级别的接口 使子系统更易于使用。”

【讨论】:

【参考方案19】:

它基本上是一个单一的窗口清除系统。你将它委托给另一个类中的特定方法的任何工作。

【讨论】:

【参考方案20】:

外观设计模式属于结构设计模式。简而言之,Facade 是指外观。这意味着在外观设计模式中,我们隐藏了一些东西,只显示客户实际需要的东西。 在下面的博客中阅读更多信息: http://www.sharepointcafe.net/2017/03/facade-design-pattern-in-aspdotnet.html

【讨论】:

【参考方案21】:

外观模式为子系统接口组提供统一的接口。外观定义了一个高级接口,它简化了子系统的工作。

【讨论】:

以上是关于什么是立面设计模式?的主要内容,如果未能解决你的问题,请参考以下文章

javascript 立面结构设计模式

Google Material Design ALL 24 立面图

模块化的至美庭院(4个)住宅设计

OnSetActive() 的“对立面”是啥?

MySQL 中 GROUP_CONCAT 的对立面是啥?

Ductal超高性能混凝土助力模块化的紧凑型建筑