Java中的外观模式

news/2024/10/7 19:26:11/文章来源:https://www.cnblogs.com/dwcg/p/18326745

Java中的外观模式

综述

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

外观模式的定义

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

外观模式的角色组成

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

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

外观模式的优缺点

它的优点在于:

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

而缺点则是:

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

外观模式的使用场景

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

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

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

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

旅行社

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

装修公司

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

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

Junit

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

Hibernate

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

外观模式的示例

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

//外观类
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);}
}

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/809553.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在C#中使用适配器Adapter模式和扩展方法解决面向的对象设计问题

之前有阵子在业余时间拓展自己的一个游戏框架,结果在实现的过程中发现一个设计问题。这个游戏框架基于MonoGame实现,在MonoGame中,所有的材质渲染(Texture Rendering)都是通过SpriteBatch类来完成的。举个例子,假如希望在屏幕的某个地方显示一个图片材质(imageTexture)…

React Fiber 原理

React Fiber 在 React 16 之前的版本对比更新 VirtualDOM 的过程是采用 Stack 架构实现的,也就是循环加递归,这种方式的问题是一旦任务开始进行就无法被中断。 如果应用中的组件数量庞大, Virtual DOM 的层级比较深,主线程被长期占用,知道整颗 Virtual DOM 树比对更新完成…

视野修炼-技术周刊第104期 | 下一代 JavaScript 工具链

① 🐙 尤大创办公司 VoidZero ② Tauri 2.0 稳定版发布 ③ Vite 时髦的新主页 ④ qrframe - 漂亮二维码生成 ⑤ HTTP QUERY 方法提案 ⑥ TinyJS - 轻量级的创建DOM元素 ⑦ 9月 Web 平台的新功能 ⑧ ESLint 现在正式支持 Linting JSON 和 Markdown欢迎来到第 104 期的【视野修…

雅礼国庆集训 day1 T2 折射

题面 题面下载 算法 转化题意 说白了就是给了你一堆点,让你数这种折线有多少个 (严格向下走,并且横坐标之间的差越来越小)看着像一种在 y 轴方向排序的 dp 但是由于是折线, 所以需要加一维来判断转向 dp 设计 状态设计 \(dp_{i, 0/1}\) 表示第 i 个点, 是向左下还是右上 状态…

React 中的 diff 算法

React diff为什么使用虚拟 DOM ? 浏览器在处理 DOM 的时候会很慢,处理 JavaScript 会很快,页面复杂的时候,频繁操作 DOM 会有很大的性能开销(每次数据变化都会引起整个 DOM 树的重绘和重排)。 为了避免频繁操作 DOM,React 会维护两个虚拟 DOM,如果有数据更新,会借此计…

20222315 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1.实验内容 1.掌握反汇编与十六进制编程器 2.能正确修改机器指令改变程序执行流程 3.能正确构造payload进行bof攻击 2.实验过程 1.直接修改程序机器指令,改变程序执行流程 将pwn1文件下载至kali中并将pwn1文件改名为pwn20222315,并将其内容复制到pwn2反汇编文件objdump -d…

多校A层冲刺NOIP2024模拟赛03

多校A层冲刺NOIP2024模拟赛03\(T1\) A. 五彩斑斓(colorful) \(90/100pts\)部分分\(20pts\) :枚举左上 \((k,h)\) 、右下端点 \((i,j)\) ,时间复杂度为 \(O(n^{2}m^{2})\) 。 \(90/100pts\) :当 \(a_{i,j} \ne a_{k,j}\) 时任意的 \(h \in [1,j]\) 都符合题意、不妨钦定 \(…

Word中 Endnote 引用标蓝色

1. 打开word中的endnote加载项。如图所示,勾选这两个设置。 确认后会自动变为超链接,显示蓝色以及下划线。 2. 在样式设置中,将超链接的下划线取消。之后就会只显示蓝色引用。 结果显示:

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1) Problem A. 贵校是构造王国吗 I 思路 官方题解很清晰明了。代码 #include <bits/stdc++.h> using namespace std; #define int long long #define endl \n #define PII pair&…

多校 A 层冲刺 NOIP2024 模拟赛 03

多校 A 层冲刺 NOIP2024 模拟赛 03 T1 五彩斑斓(colorful) 签到题 直接暴力枚举是 \(O(n^4)\) ,考虑使用 \(bitset\) 优化,对每个点开个 \(bitset\),预处理它所在一行它及它之前相同颜色的位置,这样就只用枚举另一个点所在列,时间复杂度为 \(O(n^3+\frac{n^4}{w})\)。 T…

在浏览器上访问媒体资源配置【文件上传】

1.根urls.py文件中 from django.contrib import admin from django.urls import path, include, re_path from django.views.static import serve from django.conf import settingsurlpatterns = [# path(admin/, admin.site.urls),path(api/shipper/, include(apps.shipper.u…