Java中的外观模式

1|0Java中的外观模式

1|1综述

本文总结外观模式的定义, 特点, 使用场景并给出了具体的示例.

1|2外观模式的定义

外观模式(门面模式)是一种结构型设计模式. 其主要目的是为复杂系统提供一个简化的接口. 帮助客户端代码与系统的子系统进行交互, 同时还可以省略大量的细节. 这种设计模式可以称得上设计模式中最简单的模式, 甚至可以不加"之一". 因为绝大部分的「封装」操作都可以归类到外观模式当中, 可以说很多新手开发者在没有接触过外观模式的情况下已经在不知不觉间用到了外观模式.

1|0外观模式的角色组成

在外观模式的完整模型中三个角色, 但在一些简化模型中外部调用者被省略掉了

  • 外部调用者: 外部调用者通过外观类调用子系统的功能, 在通常的模型中是隐形的, 但完整的模型中需要有它
  • 外观类: 外观类持有子系统实例, 对调用者隐藏方法的调用细节, 调用者可以通过调用外观类的方法, 调用子系统提供的功能
  • 子系统: 对外提供具体的实现功能, 模式要求至少有一个子系统

1|0外观模式的优缺点

它的优点在于:

  • 提供统一接口: 通过外观类, 将系统的复杂性隐藏起来, 提供了一个简单易用的接口给调用者.
  • 隐藏底层细节: 迪米特法则又称为最少知识原则, 此原则认为, 一个对象应当对其他对象尽可能少的了解. 而外观模式是迪米特法则的最佳实践方式之一, 它降低了调用者和子系统之间的耦合度, 使得调用者不需要了解系统内部的具体实现细节.
  • 解耦调用者和子系统: 外观类提供了一个单一的入口, 有助于提高系统的封装性和安全性.

而缺点则是:

  • 不符合开闭原则: 如果要新增或者修改子系统的功能, 需要修改外观类
  • 不适合大规模系统: 当子系统过于复杂且分散时, 或者子系统之间的交互频繁改变时, 外观模式可能也会随之频繁修改. 使用外观模式可能导致外观类变得庞大且复杂.

1|3外观模式的使用场景

外观模式的使用场景很简单

  1. 当子系统提供了过剩的自定义功能时. 注意, 这里过剩的评价标准是外部调用者用不着. 比如子系统提供对某个参数设置 1 - 100 档位的自定义功能, 但是调用者只需要 1 和 100 总计2个档位, 这就可以称为过剩.
  2. 当调用者用到了某个系统中的多个功能, 但从角色定位来说, 它不是这个系统的一员时. 这时候可以认为这个由多个子系统组成的模块应该有一个统一的接口对外提供服务. 这个统一的接口就是外观类.

所以从以上两点可以看出外观模式和封装的概念非常的相似. 事实上外观模式可以看作封装在设计模式上的拓展实现. 封装是面向对象编程的基础概念, 它可以应用于类/对象等层面, 主要目的是隐藏数据和实现细节, 通过提供公共接口来控制访问. 而外观模式关注的是隔离调用者和子系统.

这里可以用两个生活场景进行比喻说明

旅行社

旅行社通常会将多种服务, 如机票预订、酒店预订、用车服务、导游安排、门票购买等打包成一个统一的旅游套餐, 类似于「西安7天游」「广州1日游」之类的称呼. 这个旅游套餐就像是外观模式的实例, 这里子系统就是这一个个的服务提供者, 而外观类就是旅行社本身. 「西安7天游」「广州1日游」是外观类对外提供的隐藏内部子系统细节的方法, 而购买服务的顾客就是外部调用者.

装修公司

装修公司可能会提供各种家居装修包, 比如简约风格、现代风格或者新中式风格. 每个装修包包括了室内设计、材料选择、施工服务和家具搭配等. 业主可以选择一个装修包来完成整个家居装修, 而不必自行挑选和协调每个装修细节. 这里准备购买装修服务的业主就是外部调用者, 而装修公司就是外观类, 室内设计服务, 材料采购, 联系监工, 施工服务和家具定制/家具采购等都是被隐藏起来的子系统.

当然, 实际应用场景同样非常的多,典型的比如

Junit

JUnit 是一个广泛用于 Java 单元测试的框架. 尽管它的主要功能是帮助开发人员编写和运行单元测试, 但它也是一个很好的外观模式的例子. 通过 JUnit, 开发人员可以简单地编写测试用例和断言, 而无需直接与底层的测试框架或测试运行器交互.

Hibernate

Hibernate 是一个流行的对象关系映射(ORM)框架, 它简化了 Java 对象与数据库表之间的映射关系. 虽然 Hibernate 的主要目的是将对象持久化到数据库中, 但它也隐藏了底层数据库访问和 JDBC 操作的复杂性, 为开发人员提供了一个简单而强大的接口.

1|4外观模式的示例

以之前的旅行社旅游产品为例子

//外观类 public class TravelPackageFacade { private FlightBookingService flightBookingService; private HotelBookingService hotelBookingService; private CarRentalService carRentalService; private TourGuideService tourGuideService; private TicketPurchaseService ticketPurchaseService; public TravelPackageFacade() { // 初始化各个子系统服务 this.flightBookingService = new FlightBookingService(); this.hotelBookingService = new HotelBookingService(); this.carRentalService = new CarRentalService(); this.tourGuideService = new TourGuideService(); this.ticketPurchaseService = new TicketPurchaseService(); } // 提供一个简化的接口方法,封装整个旅游套餐购买过程 public void bookTravelPackage(String destination, int duration) { System.out.println("购买旅行社的 " + destination + duration + "天游 产品"); // 简化的购买流程,调用各个子系统服务 this.flightBookingService.bookFlight(destination, duration); this.hotelBookingService.bookHotel(destination, duration); this.carRentalService.rentCar(destination); this.tourGuideService.arrangeTourGuide(destination); this.ticketPurchaseService.purchaseTickets(destination); System.out.println("\n" + destination + duration + "天游 产品预定成功"); } } //各个子项目 public class FlightBookingService { public void bookFlight(String destination, int duration) { System.out.println("预定前往 " + destination + " 的机票及 " + duration + " 后的返程票"); } } public class HotelBookingService { public void bookHotel(String destination, int duration) { System.out.println("预定 " + destination + " 的酒店 " + duration + " 天"); } } public class CarRentalService { public void rentCar(String destination) { System.out.println("出租 " + destination + " 当地的旅游专车服务"); } } public class TourGuideService { public void arrangeTourGuide(String destination) { System.out.println("安排 " + destination + " 当地的导游"); } } public class TicketPurchaseService { public void purchaseTickets(String destination) { System.out.println("购买 " + destination + " 当地旅游景区套票"); } } //最后是外部调用者 public class Main { public static void main(String[] args) { var facade = new TravelPackageFacade(); facade.bookTravelPackage("西安",7); } }

1|5总结

外观模式理解简单应用广泛, 作为封装概念在设计模式上的某种实现, 只要是熟悉面向对象的开发者, 理解起来应该不需要超过半个小时, 甚至可能平时工作时不知不觉就用到了. 唯一的难点可能在于什么时候改用, 什么时候可以不用. 而这一点只能由开发者自己在开发中慢慢体会.


__EOF__

本文作者地维藏光
本文链接https://www.cnblogs.com/dwcg/p/18326745.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   地维藏光  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示