当前位置: 首页 > news >正文

万字解析设计模式之桥接模式、外观模式

一、桥接模式

1.1概述

桥接模式是一种结构型设计模式,它的作用是将抽象部分和实现部分分离开来,使它们能够独立地变化。这样,抽象部分和实现部分可以分别进行扩展,而不会相互影响。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

在桥接模式中,抽象部分和实现部分之间通过一个称为“桥”的接口进行连接。这个桥接口定义抽象部分所需要的所有方法,而实现部分则实现这些方法。这种设计方式可以使得实现部分的变化不会对抽象部分造成影响,因为抽象部分只依赖于桥接口,而不依赖于具体的实现部分。

桥接模式通常使用在需要跨越多个平台或多个产品版本的场景中。它可以提高代码的可复用性和可维护性,同时也可以使得系统更加灵活和可扩展。

现在有一个需求,需要创建不同的图形,并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系

我们可以发现有很多的类,假如我们再增加一个形状或再增加一种颜色,就需要创建更多的类。

试想,在一个有多种可能会变化的维度的系统中,用继承方式会造成类爆炸,扩展起来不灵活。每次在一个维度上新增一个具体实现都要增加多个子类。为了更加灵活的设计系统,我们此时可以考虑使用桥接模式。

 1.2结构

桥接(Bridge)模式包含以下主要角色:

  • 抽象化(Abstraction)角色 :定义抽象类,并包含一个对实现化对象的引用。
  • 扩展抽象化(Refined Abstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化(Implementor)角色 :定义实现化角色的接口,供扩展抽象化角色调用。
  • 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

 1.3实现

【例】视频播放器

需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Mac、Linux等)上播放多种格式的视频文件,常见的视频格式包括RMVB、AVI、WMV等。该播放器包含了两个维度,适合使用桥接模式。

类图如下:

实现化(Implementor)角色

package com.yanyu.Bridge;//视频文件
public interface VideoFile {void decode(String fileName);
}

具体实现化(Concrete Implementor)角色

package com.yanyu.Bridge;//avi文件
public class AVIFile implements VideoFile {public void decode(String fileName) {System.out.println("avi视频文件:"+ fileName);}
}
package com.yanyu.Bridge;//rmvb文件
public class REVBBFile implements VideoFile {public void decode(String fileName) {System.out.println("rmvb文件:" + fileName);}
}

 抽象化(Abstraction)角色

package com.yanyu.Bridge;//操作系统版本
public abstract class OperatingSystemVersion {protected VideoFile videoFile;public OperatingSystemVersion(VideoFile videoFile) {this.videoFile = videoFile;}public abstract void play(String fileName);
}

 扩展抽象化(Refined Abstraction)角色

package com.yanyu.Bridge;//Windows版本
public class Windows extends OperatingSystemVersion {public Windows(VideoFile videoFile) {super(videoFile);}public void play(String fileName) {videoFile.decode(fileName);}
}
package com.yanyu.Bridge;//mac版本
public class Mac extends OperatingSystemVersion {public Mac(VideoFile videoFile) {super(videoFile);}public void play(String fileName) {videoFile.decode(fileName);}
}

客户端类

package com.yanyu.Bridge;//测试类
public class Client {public static void main(String[] args) {OperatingSystemVersion os = new Windows(new AVIFile());os.play("战狼3");}
}

好处:

  • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。

    如:如果现在还有一种视频文件类型wmv,我们只需要再定义一个类实现VideoFile接口即可,其他类不需要发生变化。

  • 实现细节对客户透明

1.4应用场景

适合应用场景:

  • 如果你想要拆分或重组一个具有多重功能的庞杂类 (例如能与多个数据库服务器进行交互的类), 可以使用桥接模式。类的代码行数越多, 弄清其运作方式就越困难, 对其进行修改所花费的时间就越长。 一个功能上的变化可能需要在整个类范围内进行修改, 而且常常会产生错误, 甚至还会有一些严重的副作用。
  • 桥接模式可以将庞杂类拆分为几个类层次结构。 此后, 你可以修改任意一个类层次结构而不会影响到其他类层次结构。 这种方法可以简化代码的维护工作, 并将修改已有代码的风险降到最低。

1.5JDK源码解析

桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象与实现分离,使它们可以独立变化。在桥接模式中,抽象和实现可以分别在两个不同的类层次结构中定义,而通过组合的方式将它们联系起来。这样做的好处是可以减少继承带来的耦合问题,提高系统的灵活性和可扩展性。

在 JDK 中,桥接模式的应用非常广泛,下面我们分别来看几个典型的例子:

1. JDBC

在 JDBC 中,数据访问 API 和数据库驱动实现是分离的。数据访问 API 是一组接口和类,定义了数据库操作的抽象方法和常量。而具体的数据库驱动实现则是一组不同的 jar 包,每个包对应一种数据库的不同驱动实现。这样设计的好处是可以实现代码的复用,将代码的改动范围限定在实现层次结构中,不影响客户端的使用。

2. AWT

在 AWT 中,抽象窗口工具包(Abstract Window Toolkit,简称 AWT)提供了一系列抽象类和接口,用于实现和显示图形界面。而具体的 GUI 组件实现则是由不同的操作系统提供的。比如,Windows 提供的 AWT 组件实现和 Linux 提供的 AWT 组件实现是不同的,但它们都可以通过抽象类和接口来实现统一的调用方式,从而保证了跨平台的兼容性。

3. java.util.logging

在 java.util.logging 中,抽象日志记录器(Logger)定义了一组抽象方法和常量,用于记录日志信息。而具体的日志记录实现则是通过不同的日志 Handler 实现的。比如,FileHandler、ConsoleHandler、StreamHandler 等,它们都继承自抽象类 AbstractHandler,实现了具体的日志记录方式。这样设计的好处是可以将日志记录器与具体记录方式分离,提高代码的可扩展性和灵活性。

总之,桥接模式是一种非常实用的设计模式,它可以将抽象和实现分离,使它们可以独立变化。在 JDK 中,有很多典型的桥接模式应用,这些应用不仅为我们提供了很好的学习案例,还可以帮助我们更好地理解桥接模式的思想和作用。

 二、外观模式

2.1概述

外观模式(Facade Pattern)是一种结构型设计模式,它为一组复杂的子系统接口提供了一个统一的接口,以方便客户端使用。外观模式通过将复杂的系统封装在一个简单的外观对象中,简化了客户端的调用过程,同时隐藏了系统的复杂性。

外观模式通常会定义一个简单的高层接口,这个接口封装了系统的所有复杂流程和方法调用,并将这些流程和方法调用转化为若干个简单的方法,供客户端直接调用。这样客户端就不需要了解系统的内部实现细节,也不需要知道哪些子系统需要协同工作才能完成一个请求。

总的来说,外观模式提供了一种简单的方式来使用复杂系统,并使得系统更加易于使用和维护。外观(Facade)模式是“迪米特法则”的典型应用

2.2  结构

外观(Facade)模式包含以下主要角色:

  • 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
  • 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。

2.3实现

【例】智能家电控制

小明的爷爷已经60岁了,一个人在家生活:每次都需要打开灯、打开电视、打开空调;睡觉时关闭灯、关闭电视、关闭空调;操作起来都比较麻烦。所以小明给爷爷买了智能音箱,可以通过语音直接控制这些智能家电的开启和关闭。类图如下:

 

外观(Facade)角色

package com.yanyu.Facade;//智能音箱
public class SmartAppliancesFacade {//定义三个私有属性,分别代表三种电器设备private Light light;private TV tv;private AirCondition airCondition;//构造方法,初始化三种电器设备的对象public SmartAppliancesFacade() {light = new Light();tv = new TV();airCondition = new AirCondition();}//公共方法,根据语音指令控制电器的开关public void say(String message) {//如果语音指令包含“打开”,则调用on()方法if(message.contains("打开")) {on();//如果语音指令包含“关闭”,则调用off()方法} else if(message.contains("关闭")) {off();//否则,打印提示信息} else {System.out.println("我还听不懂你说的!!!");}}//私有方法,起床后一键开电器private void on() {//打印提示信息System.out.println("起床了");//调用三种电器设备的on()方法,分别开启灯、电视和空调light.on();tv.on();airCondition.on();}//私有方法,睡觉一键关电器private void off() {//打印提示信息System.out.println("睡觉了");//调用三种电器设备的off()方法,分别关闭灯、电视和空调light.off();tv.off();airCondition.off();}
}

定义了一个智能音箱类,作为三种电器设备的门面,提供了一个统一的接口,使得客户端可以通过语音指令来控制电器的开关,而不需要了解电器的具体实现细节。外观模式可以简化客户端与子系统之间的交互,降低系统的复杂度和耦合度

 子系统(Sub System)角色

package com.yanyu.Facade;//灯类
public class Light {public void on() {System.out.println("打开了灯....");}public void off() {System.out.println("关闭了灯....");}
}
package com.yanyu.Facade;//电视类
public class TV {public void on() {System.out.println("打开了电视....");}public void off() {System.out.println("关闭了电视....");}
}
package com.yanyu.Facade;//空调类
public class AirCondition {public void on() {System.out.println("打开了空调....");}public void off() {System.out.println("关闭了空调....");}
}

客户端类

package com.yanyu.Facade;//测试类
public class Client {public static void main(String[] args) {//创建外观对象SmartAppliancesFacade facade = new SmartAppliancesFacade();//客户端直接与外观对象进行交互facade.say("打开家电");facade.say("关闭家电");}
}
  • 对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。
  • 当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问。
  • 当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性。

2.4应用场景

  • 对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。
  • 当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问。
  • 当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性。

三、 桥接模式实验

任务描述

某软件公司欲开发一个数据转换工具,可以将数据库中的数据转换成多种文件格式,例如 TXT、XML、PDF 等格式,同时该工具需要支持多种不同的数据库。

本关任务:用桥接模式对模拟程序进行框架搭建,如图。

,

实现方式

  1. 明确类中独立的维度。 独立的概念可能是: 抽象/平台, 域/基础设施, 前端/后端或接口/实现。

  2. 了解客户端的业务需求, 并在抽象基类中定义它们。

  3. 确定在所有平台上都可执行的业务。 并在通用实现接口中声明抽象部分所需的业务。

  4. 为你域内的所有平台创建实现类, 但需确保它们遵循实现部分的接口。

  5. 在抽象类中添加指向实现类型的引用成员变量。 抽象部分会将大部分工作委派给该成员变量所指向的实现对象。

  6. 如果你的高层逻辑有多个变体, 则可通过扩展抽象基类为每个变体创建一个精确抽象。

  7. 客户端代码必须将实现对象传递给抽象部分的构造函数才能使其能够相互关联。 此后, 客户端只需与抽象对象进行交互, 无需和实现对象打交道。

编程要求

根据提示,在右侧编辑器 Begin-End 内补充 "DataHandler.java"、"FileConvertor.java"、"PDFConvertor.java"、"XMLConvertor.java" 和 "TXTConvertor.java" 文件的代码。

测试说明

平台会自动从 xml 文件中读取内容,然后对你编写的代码进行测试:

预期输出: 从Oracle数据库中读取数据 转换成PDF格式的数据

预期输出: 从SQLServer数据库中读取数据 转换成TXT格式的数据

客户端类

package step1;import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;public class XMLUtils {//定义一个静态方法,根据传入的标签名,返回对应的类的实例对象public static Object getBean(String name) {try {//创建DOM文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;//解析XML文件,获取Document对象doc = builder.parse(new File("/data/workspace/myshixun/src/config.xml"));//获取包含类名的文本结点NodeList nl = doc.getElementsByTagName(name);Node classNode = nl.item(0).getFirstChild();//获取结点的值,即类名String cName = classNode.getNodeValue();//通过类名生成实例对象并将其返回Class c = Class.forName(cName);Object obj = c.getDeclaredConstructor().newInstance();return obj;}catch(Exception e) {//捕获并打印异常e.printStackTrace();return null;}}
}

这段代码是一个XML工具类,它使用了DOM方式来解析XML文件,获取其中的类名,并通过反射机制来创建类的实例对象。这样可以实现配置文件和代码的分离,提高代码的可维护性和可扩展性 

package step1;public class Client {public static void main(String[] args) {//创建一个抽象化角色的对象,通过XML配置文件获取其具体实现类的名称FileConvertor fileConvertor = (FileConvertor) XMLUtils.getBean("className1");//将一个实现化角色的对象注入到抽象化角色中,通过XML配置文件获取其具体实现类的名称fileConvertor.setDataHandler((DataHandler) XMLUtils.getBean("className2"));//调用抽象化角色的方法,实现对文件的转换fileConvertor.translate();}
}

 实现化角色


package step1;/********** Begin *********/
//定义一个抽象的数据处理类,作为实现化角色
public abstract class  DataHandler{//定义一个抽象的数据读取方法,由子类实现public abstract void readData();
}/********** End *********/

具体实现化角色

package step1;//定义一个从Oracle数据库中读取数据的类,继承自DataHandler类,作为具体实现化角色
public class OracleHandler extends  DataHandler{//重写父类的抽象方法,实现具体的数据读取操作@Overridepublic void readData() {System.out.println("从Oracle数据库中读取数据");}
}
package step1;public class SQLServerHandle extends DataHandler{@Overridepublic void readData() {System.out.println("从SQLServer数据库中读取数据");}
}

抽象化角色

package step1;/********** Begin *********/
//定义一个抽象的文件转换类,作为抽象化角色
public abstract class  FileConvertor{//定义一个受保护的数据处理类的引用,作为实现化角色的接口protected DataHandler handler;//定义一个公共的方法,用于设置数据处理类的对象,实现桥接的过程public void setDataHandler(DataHandler handler) {this.handler = handler;}//定义一个抽象的方法,用于转换文件,由子类实现,调用数据处理类的方法public abstract void translate();}/********** End *********/

扩展抽象类

package step1;//定义一个PDF文件转换类,继承自FileConvertor类,作为扩展抽象化角色
public class PDFConvertor extends FileConvertor{//重写父类的抽象方法,实现具体的文件转换操作@Overridepublic void translate() {/********** Begin *********///调用实现化角色的方法,读取数据handler.readData();/********** End *********///打印提示信息,表示转换成PDF格式的数据System.out.println("转换成PDF格式的数据");}
}
package step1;public class TXTConvertor extends FileConvertor{@Overridepublic void translate() {/********** Begin *********/handler.readData();/********** End *********/System.out.println("转换成TXT格式的数据");}
}
package step1;public class XMLConvertor extends FileConvertor{@Overridepublic void translate() {/********** Begin *********/handler.readData();/********** End *********/System.out.println("转换成XML格式的数据");}
}

相关文章:

万字解析设计模式之桥接模式、外观模式

一、桥接模式 1.1概述 桥接模式是一种结构型设计模式,它的作用是将抽象部分和实现部分分离开来,使它们能够独立地变化。这样,抽象部分和实现部分可以分别进行扩展,而不会相互影响。它是用组合关系代替继承关系来实现,…...

常用系统函数

$clog2 clogb2 系统函数 $clog2 应返回参数以 2 为底的对数的上限(对数四舍五入为整数值)。参数可以是整数或任意大小的向量值。参数应被视为无符号值,参数值为 0 将产生结果 0。 该系统函数可用于计算对给定大小的存储器进行寻址所…...

键盘控制ROS车运动

键盘控制ROS车运动 上位机 使用pyseria库与stm32单片机进行通信控制 #!/usr/bin/env python # -*- coding: utf-8 -*import sys, select, termios, tty import serialmsg """ ---------------------------w a x ds w : x a : y s : -x …...

linux上交叉编译qt库

linux上交叉编译qt库 Qt程序从X86平台Linux移植到ARM平台Linux需要做什么 1.在ubuntu上使用qt的源码交叉编译出Qt库 2.将编译好的库拷贝到开发板上并设置相应的环境变量(库路径啥的) 前两步一劳永逸,做一次就行 3.X86上写好程序代码&…...

Nacos介绍与使用

Nacos介绍与使用 文章目录 Nacos介绍与使用一. 什么是Nacos1 Nacos功能1.1 配置中心1.2 注册中心 2.为什么要使用Nacos 二.Nacos 部署安装1. Nacos 部署方式2. Nacos 安装3. 配置数据源4. 开启控制台授权登录(可选) 三. Nacos配置中心的使用1. 创建配置信…...

网工内推 | 字节原厂,正式编,网络工程师,最高30K*15薪

01 字节跳动 招聘岗位:网络虚拟化高级研发工程师 职责描述: 1、负责字节跳动虚拟网络产品的研发,包括但不局限于网络VPC、NAT、LB负载均衡等; 2、负责字节跳动网络基础平台的研发,包括但不局限于网络控制面系统、容器…...

Git 远程仓库(Github)

目录 添加远程库 查看当前的远程库 提取远程仓库 推送到远程仓库 删除远程仓库 Git 并不像 SVN 那样有个中心服务器。 目前我们使用到的 Git 命令都是在本地执行,如果你想通过 Git 分享你的代码或者与其他开发人员合作。 你就需要将数据放到一台其他开发人员…...

Mybatis Plus分页实现逻辑整理(结合芋道整合进行解析)

Mybatis Plus分页实现逻辑整理(结合芋道整合进行解析) 我希望如春天般的你,身着白色的婚纱,向我奔赴而来,我愿意用全世界最温情的目光,朝着你的方向望去——姗姗来迟。 1.背景介绍 https://baomidou.com/p…...

C#编程题分享(2)

输出所有整数的和 让⽤户输⼊整数,如果⽤户输⼊的不是0,就继续输⼊,如果输⼊的是0,结束整数,并输出所有整数的和。 Console.WriteLine("请输⼊⼀个整数:"); int n; int sum 0; do {n Convert…...

Dockerfile基础

前言 知识点整理 Dockerfile 简介 它是一个没有后缀名的文本文档,里面是组合镜像的一些命令,Docker build命令构建镜像时,通过读取Dockerfile中的指令的顺序(自上到下)自动生成镜像。 Dockerfile 命令 1. FROM 指…...

python+selenium实现web自动化(基础入门)

selenium 是一个自动化操控工具,支持对web端进行自动化操控,从而实现自动化测试。 相关文档: https://python-selenium-zh.readthedocs.io/zh-cn/latest/https://www.selenium.dev/documentation/ 安装配置 环境依赖: python…...

Spring Boot 自动配置

1. Spring Boot 自动配置 Spring Boot的自动配置是其核心特性之一,旨在简化Spring应用程序的配置过程。这个特性通过合理的默认值以及根据类路径和其他因素自动配置Spring Beans来极大地减少了配置的工作量。以下是Spring Boot自动配置的详细讲解: 基本…...

力扣labuladong一刷day13天双指针8道链表题

力扣labuladong一刷day13天双指针7道链表题 一、21. 合并两个有序链表 题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/ 思路:合并只需要新new一个虚拟头结点,然后遍历比较两个链表把较小的那一个顺序接在虚拟头结点后面。…...

【剑指offer|图解|链表】链表的中间结点 + 链表中倒数第k个结点

🌈个人主页:聆风吟 🔥系列专栏:数据结构、算法模板 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋前言一. ⛳️链表的中间结点二. ⛳️链表中倒数第k个结点📝结语 &#x1f4c…...

被环境变量虐过一遍获得的启示

Oracle数据库环境存在两个数据库版本12C及19C,在执行一些操作时需要设置对应版本的环境变量 计划登录12C环境,于是按如下方式设置环境变量 export ORACLE_BASE/u01/app/oracle export ORACLE_HOME$ORACLE_HOME/product/12.2.0/dbhome_1 export ORACLE_S…...

关于Hbase的一些问题

HBase 1. RowKey如何设计,设计不好会产生什么后果 唯一原则:在设计上要保持RowKey的唯一性。 因为HBase中的数据是以KV的格式来存储的,所以如果向同一张表中插入RowKey相同的数据,旧的数据会被覆盖掉。 长度原则:建…...

level=warning msg=“failed to retrieve runc version: signal: segmentation fault“

安装docker启动后,发现里面没有runc版本信息 目前看是少了runc组件 那我们安装runc https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64 [rootlocalhost ~]# mv runc.amd64 /usr/bin/runc mv:是否覆盖"/usr/bin/runc&q…...

电力工作记录仪、智能安全帽、智能布控球助力智能电网建设

电力行业的建设和发展是国家经济发展的重要支撑,而智能电网作为电力系统的重要组成部分,它的安全高效运行关乎到整个电力系统乃至民生的稳定和安全。为了加快国家经济的发展以及满足人们对电力的需求和用电可靠性的要求,国家早在十二规划中就…...

【CSS】各百分比透明度 opacity 对应的 16 进制颜色值(例如:#FFFFFF80)

文章目录 使用:6位颜色值2位透明度值 color: #000000D4; /* 等价于 */ color: #000000; opacity : 0.83; /* 等价于 */ color: #000000; opacity : 83%; 对照表(0:完全透明,1:不透明) 透明度值百分百值十…...

有依次对应关系的数组X、Y、Z,如何排序其中一个X数组,使得另外的数组还与排序完成后的数组相对应(C语言实现)

1. 目的 有依次对应关系的数组X、Y、Z,排序其中一个X数组,使得另外的数组还与排序完成后的数组相对应,并打印出排序完成后的X、Y、Z数组。 2. 具体实现 以下面的这个对应关系为例,进行相应编程实现。 X [3.7,7.7,-6.6,1.5,-4.5…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

【kafka】Golang实现分布式Masscan任务调度系统

要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

浅谈不同二分算法的查找情况

二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况&#xf…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 ​…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...