软件模块的耦合

软件模块的耦合

  • 无直接耦合
  • 数据耦合
  • 标记耦合
  • 控制耦合
  • 外部/通信耦合
  • 公共耦合
  • 内容耦合
  • 最后

良好的软件模块的设计,需要遵守低耦合,高内聚。这将在代码维护中发挥重要的作用。本文将重点阐述七种耦合以及他们的区别,耦合程度由低到高:无直接耦合–>数据耦合–> 标记耦合 --> 控制耦合 --> 外部耦合 --> 公共耦合 -->内容耦合 。

无直接耦合

1.一组没有直接关系模块,这里是理想的状态。

数据耦合

1.通过基本数据联结,模块之间仅通过传递必要的基本数据值(整数、字符串等)进行通信。依赖最小化,接口清晰,修改影响小。是优秀的耦合类型。

2.代码示例:

# 好的数据耦合defcalculate_area(width,height):# 只传递必需的基本数据returnwidth*height area=calculate_area(10,5)# 调用简单清晰

标记耦合

1.通过数据结构联结。包含多余信息的“数据包裹,暴露了不必要的信息,产生隐含依赖。并且数据结构发生更改,被调用模块将重写。常见但不够理想的做法。理想的做法是转为数据耦合。

2.例子:

  • 订单模块在创建订单时,只需要userIdaddress
  • 调用方式createOrder(struct UserInfo user);
  • 解释:调用者传递了整个UserInfo结构体。虽然功能上没问题,但订单模块现在“知道”了太多它本不需要知道的用户信息(如email,birthDate,loyaltyPoints)。它和UserInfo这个数据结构形成了耦合。如果未来UserInfo结构改变(即使只是增加一个不相关的字段),createOrder函数和订单模块可能都需要重新编译。

3.危害

降低可维护性:对数据结构的无关修改会产生“涟漪效应”,导致依赖它的所有模块都需要重新检查、编译和测试,增加了维护成本。
降低可读性:函数签名createOrder(UserInfo user)不如createOrder(int userId, Address addr)清晰。后者一眼就能看出该函数需要什么。
增加错误风险:因为模块可以访问多余的数据,开发者可能会在无意中错误地使用了这些数据(例如,本应用address,却误用了email)。
降低复用性:订单模块与特定的UserInfo结构紧密绑定。如果想在另一个不使用UserInfo结构的项目中复用订单模块,会非常困难。

控制耦合

1.一个模块通过控制参数/标志/命令控制另一个模块的内部逻辑流程。调用模块需要知道被调用模块的逻辑,当被调用模块发生更改,例如加条件分支, 调用模块需要更改。

2.例子:点咖啡的诡异对话:

你:用“模式A”做咖啡
店员听到“模式A”后,内部执行一套复杂操作:

  1. 先磨豆子

  2. 如果周二就加奶油

  3. 如果下雨就少加冰

你实际上在远程控制店员的大脑决策流程!

3.代码示例:

# 控制耦合 - 糟糕的设计defprocess_order(order,special_mode):ifspecial_mode=="MODE_A":# 执行10个步骤elifspecial_mode=="MODE_B":# 执行另一套逻辑# ...# 调用者必须知道内部逻辑process_order(order,"MODE_A")

4.控制耦合危害:
调用者需要知道被调用者的内部实现细节
被调用模块的行为难以预测
增加一个模式就要修改代码
改进:应该拆分成不同的函数,如 make_latte()、make_cappuccino()。

外部/通信耦合

模块间通过外部环境[软件之外]联结【如I/O将模块耦合到特定外部系统/设备, 数据库, 配置文件,格式规则,通信协议/接口】,共享输入或者输出。模块本身不更改外部环境,但外部环境的更改将影响所有模块,更改后可能需要重连或者重启动。

公共耦合

1.一组模块共享公共数据环境,各模块任意读写,立刻感知,容易造成数据混乱和程序bug。

2.外部耦合 vs. 公共耦合

这两个概念容易混淆,因为它们都涉及“共享”。按照笔者的理解:外部耦合为共享模块进程之的系统或者设备,或者文件规则。公共耦合为共享模块进程内部的内存数据。以下以办公室的不同共享方式为比喻,来阐述两种耦合的区别。

公共耦合 = 共享的可随意涂改的白板

  • 办公室有一块公共白板,每个人都可以随时上去写字、擦掉别人的字
  • 小明在上面写了个会议时间
  • 小红觉得时间不对,直接擦掉改了
  • 小刚又在上面画了个图表
  • 结果:白板内容乱七八糟,谁也不知道现在哪个信息是准确的

外部耦合 = 共享的打印机

  • 办公室所有人都用同一台打印机
  • 打印机有自己的设置:默认双面打印、A4纸型、特定页边距
  • 如果打印机设置改了(比如变成单面打印),所有人的打印效果都变了
  • 但没人能直接修改打印机硬件本身,只能使用它

本质区别对比表

维度公共耦合外部耦合
共享什么同一个内存中的数据结构同一个外部系统/环境
谁能修改所有模块都能直接读写外部实体控制,模块只能遵守(遵守规则)
修改方式直接赋值、修改内存通过配置、协议、接口间接影响
可见性立即影响所有使用者改变后,所有使用者下次访问时受影响
典型例子全局变量、静态类字段、单例文件格式、数据库模式、API协议、操作系统

公共耦合示例:全局记账本

# 全局变量 - 公共数据区company_account={"balance":10000,# 公司总余额"transactions":[]# 交易记录}# 模块A:销售部门defsales_department(amount):company_account["balance"]+=amount company_account["transactions"].append(f"销售收入: +{amount}")# 问题:直接修改了全局数据# 模块B:采购部门defpurchase_department(amount):company_account["balance"]-=amount# 问题:可能和销售部门同时修改,导致数据不一致company_account["transactions"].append(f"采购支出: -{amount}")# 模块C:财务部门deffinance_department():# 依赖全局数据,但不知道谁改了它print(f"当前余额:{company_account['balance']}")# 如果balance被意外修改,这里显示错误数据

问题特征:

  • 所有函数都能直接读写company_account
  • 没有访问控制
  • 一个部门的错误会影响所有部门

外部耦合示例:共享数据库表结构

# 所有模块都依赖同一个数据库表结构# users表结构:# id (INT)# name (VARCHAR)# email (VARCHAR)# created_at (DATETIME)# 模块A:用户注册defregister_user(name,email):# SQL依赖特定的表结构sql="INSERT INTO users (name, email, created_at) VALUES (%s, %s, NOW())"# 如果表结构改了,比如删除了email字段,这里就出错execute_sql(sql,[name,email])# 模块B:查询用户defget_user_report():# 同样依赖users表结构sql="SELECT name, email FROM users WHERE created_at > '2024-01-01'"# 如果字段名改了,这里也出错returnexecute_sql(sql)# 模块C:数据导出defexport_users():# 还是依赖同一个表结构sql="SELECT * FROM users ORDER BY created_at"# 增加新字段可能破坏导出格式returnexecute_sql(sql)

问题特征:

  • 所有模块都依赖同一个外部约定(数据库表结构)
  • 不能直接修改数据库,但数据库的改动会影响所有模块。[数据库表的更改一般由DBA执行DDL语句进行操作]
  • 耦合的是接口/协议,不是内存数据

解决公共耦合

# 错误:公共耦合global_data={"value":0}# 方案1:依赖注入(推荐)classDepartment:def__init__(self,account):self.account=account# 传入依赖,不直接访问全局# 方案2:不可变数据fromfrozendictimportfrozendict shared_config=frozendict({"version":"1.0"})# 只能读,不能改# 方案3:访问控制classAccountManager:def__init__(self):self._balance=10000# 私有defget_balance(self):# 只读接口returnself._balancedefupdate_balance(self,amount,reason):# 受控修改# 记录日志、验证等self._balance+=amount

解决外部耦合

# 错误:硬编码外部依赖defprocess_data():data=read_xml("data.xml")# 硬编码文件格式# 处理XML...# 方案1:抽象接口classDataReader:defread(self,filename):passclassXMLReader(DataReader):defread(self,filename):# 读取XMLclassJSONReader(DataReader):defread(self,filename):# 读取JSON# 方案2:配置化classConfig:FILE_FORMAT=os.getenv("DATA_FORMAT","json")# 从环境变量读取# 方案3:适配器模式classDataAdapter:def__init__(self,format_type):self.format_type=format_typedefload(self,filename):ifself.format_type=="xml":returnXMLReader().read(filename)elifself.format_type=="json":returnJSONReader().read(filename)

在实际项目中:

  • 公共耦合几乎总是设计错误,应该立即重构
  • 外部耦合有时不可避免(如使用行业标准),但应通过[抽象]来隔离变化

记住这个关键区别:公共耦合是内部数据共享混乱,外部耦合是外部依赖约束太紧。

内容耦合

(1)一个模块直接访问另一个模块的内部数据。
(2)一个模块不通过正常入口转到另一模块内部。
(3)两个模块有一部分程序代码重迭。
(4)一个模块有多个入口。

内容耦合是最糟糕的耦合类型,就像是直接侵入别人大脑进行控制。

情况1:直接访问另一个模块的内部数据。就像直接打开同事的抽屉,拿走他私藏的零食,还修改了他的私人日记。

// module_a.c - 被侵入的模块#include<stdio.h>// 这是模块A的私有内部数据,外界不该知道staticintsecret_counter=42;// static表示模块私有的staticcharprivate_buffer[100]="机密信息";voidpublic_function(){printf("正常执行,counter=%d\n",secret_counter);}// module_b.c - 侵入者模块#include<stdio.h>// 邪恶操作:声明要访问module_a的私有变量externintsecret_counter;// 用extern声明外部变量externcharprivate_buffer[];voidhack_module_a(){printf("我是模块B,我要搞破坏!\n");// 直接修改module_a的私有数据secret_counter=999;// 本来应该是module_a内部控制的// 甚至修改module_a的私有缓冲区strcpy(private_buffer,"我被黑了!");printf("成功侵入,改了counter和buffer\n");}// main.cintmain(){public_function();// 输出:正常执行,counter=42hack_module_a();// 模块B侵入修改public_function();// 输出:正常执行,counter=999 (数据被篡改!)return0;}

破坏性:模块B完全绕过了模块A的封装,直接操作其内部状态。如果模块A改变内部实现(比如重命名secret_counter),模块B就会崩溃。

情况2:不通过正常入口转到另一模块内部。就像不在商店正门进入,而是翻窗户直接跳到柜台后面开始操作收银机。

代码示例(汇编/GOTO版本)

// 假设这是模块Avoidprocess_order(){start:printf("开始处理订单...\n");// ... 一些订单处理逻辑 ...middle_of_function:// 这是一个标签,不是正常的调用入口printf("正在计算价格...\n");// ... 价格计算逻辑 ...end:printf("订单完成\n");}// 模块B的邪恶操作voidevil_jump(){printf("我要直接跳到模块A中间执行!\n");// 在一些古老/底层的编程方式中,可能这样跳转// 这完全破坏了函数调用的堆栈和上下文// goto middle_of_function; // 如果允许的话// 现代语言通常禁止这种跨函数的goto// 但在汇编中完全可能:// jmp middle_of_function}

现代语言中的变种(通过反射/指针黑客)

# Python中通过修改函数字节码或利用反射进行破坏importtypes# 模块A的正常函数defcalculate_discount(price):"""计算折扣"""print(f"计算价格:{price}")discount=price*0.9# 打9折returndiscount# 模块B的邪恶操作defhijack_function():"""劫持模块A的函数"""# 获取函数的代码对象original_code=calculate_discount.__code__# 创建恶意代码(实际中更复杂)# 这里简化表示:直接修改函数行为defevil_calculate_discount(price):print("哈哈,我劫持了这个函数!")returnprice*0.5# 改成5折,完全破坏业务逻辑# 替换函数实现calculate_discount.__code__=evil_calculate_discount.__code__# 测试print("正常调用:",calculate_discount(100))# 输出: 90.0hijack_function()print("被劫持后:",calculate_discount(100))# 输出: 50.0

破坏性:跳过了函数的初始化代码,可能导致变量未初始化、堆栈混乱等问题。

情况3:两个模块有一部分程序代码重迭。就像两个部门共用同一本工作手册,其中一个部门撕掉了几页,另一个部门就用不了了。内存共享代码。

// 在早期计算机内存紧张的时代,可能会这样做// 假设有两个函数共享同一段机器码// 函数A和函数B共享前10条指令// 在汇编中可能这样写:/* function_a: push bp mov bp, sp ; ... 共享的前10条指令 ... ; 然后分支 jmp unique_part_a function_b: push bp mov bp, sp ; ... 和function_a完全相同的前10条指令 ... jmp unique_part_b ; 内存中实际上只存了一份前10条指令 ; function_a和function_b指向同一块内存 */// 现代高级语言中很少见,但可以用函数指针模拟这种"共享"voidshared_code_part(){printf("这是共享的代码部分\n");}voidfunction_a(){shared_code_part();printf("函数A特有的部分\n");}voidfunction_b(){shared_code_part();// 重用同一段代码printf("函数B特有的部分\n");}// 破坏性的情况:如果shared_code_part被修改// 两个函数都会受到影响,而且可能互相干扰

破坏性:一个模块的修改会直接影响另一个模块,因为它们共享同一段物理代码。

情况4:一个模块有多个入口。就像一个自动售货机,除了正常的投币口,侧面还有一个维修口,顾客可以从维修口直接拿商品。

// 模块:计算器// 不正常的多个入口点#include<stdio.h>// 正常的入口点voidcalculator(){intchoice;floata,b;start:// 入口1:函数开头printf("\n=== 计算器 ===\n");printf("1. 加法\n2. 减法\n");printf("选择: ");scanf("%d",&choice);// 邪恶的第二个入口点if(choice==666){gotosecret_entry;// 跳转到函数中间}printf("输入两个数: ");scanf("%f %f",&a,&b);if(choice==1){printf("结果: %.2f\n",a+b);}elseif(choice==2){printf("结果: %.2f\n",a-b);}return;// 正常返回secret_entry:// 入口2:函数中间的标签printf("你发现了秘密入口!\n");printf("直接执行乘法...\n");// 跳过输入,使用预设值printf("结果: %.2f\n",10.0*20.0);// 跳回正常流程gotostart;}// 更糟糕的情况:函数指针指向函数中间voidcalculator_multi_entry(){// 函数体...}voidsecret_functionality(){printf("秘密功能\n");}intmain(){// 正常的函数调用calculator();// 邪恶的调用方式:获取函数内部地址并跳转// 在一些底层编程中,可以获取标签地址// void (*secret_ptr)() = &secret_entry; // 如果允许获取标签地址// secret_ptr(); // 直接跳到函数中间执行return0;}

破坏性:破坏了函数的单一职责原则,使得函数状态难以管理,调用者需要知道函数内部的实现细节。

现实中的内容耦合(虽然少见但存在)

  1. 直接内存修改
// 游戏外挂:直接修改游戏内存// 外挂程序找到游戏中的金钱地址,直接写入99999// 这就是典型的内容耦合:外挂依赖于游戏的内存布局
  1. 通过反射破坏封装
// Java反射可以访问私有字段publicclassBankAccount{privatedoublebalance=1000;// 私有字段publicdoublegetBalance(){returnbalance;}}// 攻击代码FieldbalanceField=BankAccount.class.getDeclaredField("balance");balanceField.setAccessible(true);// 破坏封装性!balanceField.set(account,999999);// 直接修改私有字段
  1. 共享内存/消息队列的滥用
# 两个进程通过共享内存通信# 进程A直接把内部数据结构指针给进程B# 进程B直接修改这些数据,绕过所有安全检查

如何避免内容耦合?

  1. 严格遵守封装原则
    • 所有数据私有化
    • 通过公共方法访问数据。

在面向对象中,特征之一即为封装,遵循信息隐蔽原则。这里的‘信息隐蔽’不是隐私,而实为了降低模块的耦合,提升代码的维护。

  1. 使用设计模式

    // 使用观察者模式而不是直接访问classSubject{privateList<Observer>observers=newArrayList<>();// 不暴露内部列表,只提供订阅方法publicvoidaddObserver(Observero){observers.add(o);}}
  2. 避免使用破坏封装的语言特性

    • 慎用反射
    • 避免直接内存操作
    • 不使用goto(特别是跨函数)
  3. 单一入口原则

    # 好的设计:单一入口classPaymentProcessor:defprocess(self,amount,method):# 只有一个公共入口ifmethod=="credit":returnself._process_credit(amount)elifmethod=="paypal":returnself._process_paypal(amount)def_process_credit(self,amount):# 私有方法# 实现细节def_process_paypal(self,amount):# 私有方法# 实现细节

内容耦合的识别标志

标志例子
使用extern访问其他模块的静态变量extern int other_module_private;
使用反射访问私有成员field.setAccessible(true)
函数内部有多个goto标签可作为入口start:middle:end:
两个函数共享全局变量进行隐式通信全局变量作为"后门"
使用函数指针指向函数中间地址void (*p)() = &label_in_middle;

记住:内容耦合是软件工程中的"七宗罪"之一,一旦发现就应该立即重构!

最后

在耦合谱系中的位置

耦合度从低到高通常排列为:

  1. 无直接耦合-> 2.数据耦合-> 3.标记耦合-> 4.控制耦合-> 5.外部耦合-> 6.公共耦合-> 7.内容耦合

标记耦合处于中低水平。在现代面向对象编程中,它非常普遍(例如,传递一个对象作为参数),通常被认为是一种 “可接受的妥协” ,尤其是在模块边界清晰、且数据结构相对稳定的情况下。但它仍然是代码设计中需要警惕的信号,思考接口是否可以进一步精简。优秀的软件设计应致力于向数据耦合靠拢,使模块间的连接尽可能简洁、明确。控制耦合应该遵循单一职责原则进行分离。外部耦合有时不可避免(如使用行业标准),但应通过[抽象]来隔离变化。公共耦合内容耦合几乎总是设计错误,应该立即重构。


愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!

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

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

相关文章

用Sambert-HifiGan为电子书添加语音:自动化有声书制作

用Sambert-HifiGan为电子书添加语音&#xff1a;自动化有声书制作 引言&#xff1a;让文字“开口说话”——中文多情感语音合成的现实需求 在数字阅读日益普及的今天&#xff0c;电子书已不再是静态文本的简单集合。越来越多用户希望获得更沉浸、更便捷的听觉体验——通勤时听一…

光伏三相并网仿真研究:MPPT控制与高效功率输出的动态分析与优化

光伏三相并网仿真 模型内容&#xff1a; 1.光伏MPPT控制两级式并网逆变器&#xff08;boost三相桥式逆变&#xff09; 2.坐标变换锁相环dq功率控制解耦控制电流内环电压外环控制spwm调制 3.LCL滤波 仿真结果&#xff1a; 1.逆变输出与三项380V电网同频同相 2.直流母线电压800V稳…

3Flag;MDYKDHDGDYKDHDIDYKDDDDKL

一、基础性质 英文名称&#xff1a;3Flag Tag&#xff1b;Triple Flag Tag&#xff1b;MDYKDHDGDYKDHDIDYKDDDDKL peptide中文名称&#xff1a;三重复 Flag 标签肽&#xff1b;3Flag 融合标签&#xff1b;人工设计 22 肽检测纯化标签多肽序列&#xff1a;H-Met-Asp-Tyr-Lys-As…

随笔小计-前端经常接触的http响应头(跨域CORS,性能-缓存-安全,token)

在前端开发中&#xff0c;响应头由后端或服务器设置&#xff0c;前端开发需要理解其含义&#xff0c;以便调试跨域&#xff0c;缓存&#xff0c;安全性能等问题。1.CORS-跨域响应头说明Access-Control-Allow-Origin允许哪些源访问资源&#xff08;如 * 或 https://your-site.co…

IntelliJ IDEA 各版本

IntelliJ IDEA 各版本主要分为 社区版 和 终极版 两大系列&#xff0c;以下是详细区别&#xff1a; 一、主要版本类型 1. IntelliJ IDEA Community&#xff08;社区版&#xff09; 免费开源&#xff0c;遵循 Apache 2.0 许可证核心功能&#xff1a; Java SE 开发Kotlin 开发…

复杂背景下的OCR识别:CRNN模型的解决方案

复杂背景下的OCR识别&#xff1a;CRNN模型的解决方案 &#x1f4d6; 项目简介 在数字化转型加速的今天&#xff0c;OCR&#xff08;光学字符识别&#xff09;技术已成为信息自动化处理的核心工具之一。从发票扫描、证件录入到文档电子化&#xff0c;OCR 能够将图像中的文字内容…

热销榜单:2026年EOR名义雇主服务品牌排行榜,助力企业灵活用工的五大优势

EOR名义雇主正在成为现代企业灵活用工的重要选择。在2026年品牌排行榜中&#xff0c;各大服务提供商展现出其独特优势&#xff0c;帮助企业在国际市场上更有效地管理人力资源。EOR名义雇主服务不仅能够降低管理成本&#xff0c;还确保企业遵循各国法规&#xff0c;提升了用工的…

COMSOL二维仿真:电磁超声Lamb波在板材检测中的应用——适合新手入门学习使用

COMSOL二维仿真 电磁超声Lamb波对板材检测 适合新手入门学习使用电磁超声检测这玩意儿听起来挺玄乎&#xff0c;其实用COMSOL玩起来就跟搭积木差不多。今儿咱们就拿块铝板做实验&#xff0c;手把手教你用二维仿真抓Lamb波的尾巴。别慌&#xff0c;就算你昨天刚装好软件&#xf…

Thinkphp-Laravel+uniapp微信小程序的个人健康评估管理系统

目录个人健康评估管理系统摘要项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理个人健康评估管理系统摘要 该系统基于ThinkPHP或Laravel框架构建后端&#xff0c;结合UniApp开发微信小程序前端&#xff0c;实现个人健康数据的综合管理与评估。系统…

L298N电机驱动模块去耦电容配置实战案例

L298N驱动直流电机的电源“稳压秘籍”&#xff1a;去耦电容实战全解析你有没有遇到过这样的场景&#xff1f;代码写得滴水不漏&#xff0c;PID参数调得明明白白&#xff0c;结果电机一启动——主控芯片突然复位、串口通信断连、传感器数据乱跳。排查半天&#xff0c;程序没毛病…

成功案例|如何进行定岗定编体系设计?——华恒智信助力某度假村林果部科学配员与弹性用工实例

【导读】企业是否面临过这样的问题&#xff0c;不论怎么努力部门的投入和产出总是不能达到平衡&#xff1b;工作无法机械化以至于员工人数不够&#xff1b;企业的不知道怎么进行合理的人员配置&#xff0c;是应该内部管理还是外包出去&#xff1f;该度假村酒店目前就面临着这些…

用Sambert-HifiGan为游戏NPC添加生动语音对话

用Sambert-HifiGan为游戏NPC添加生动语音对话 引言&#xff1a;让NPC“说人话”——中文多情感语音合成的必要性 在现代游戏开发中&#xff0c;NPC&#xff08;非玩家角色&#xff09;不仅是任务传递者或背景填充物&#xff0c;更是构建沉浸式世界观的关键一环。然而&#xff0…

Java开发者也能玩转AI视频生成?手把手教你部署

Java开发者也能玩转AI视频生成&#xff1f;手把手教你部署 从零开始&#xff1a;Java背景工程师的AI实践之路 在传统企业级开发中&#xff0c;Java一直是后端服务、中间件和高并发系统的首选语言。然而随着AIGC浪潮席卷全球&#xff0c;越来越多开发者希望涉足AI领域——但面对…

在 ABAP Cloud 里优雅读取与解析 XML:用 sXML Reader 把接口数据落成结构化 ABAP

在接口世界里,JSON 很流行,XML 依旧很顽强:不少老牌企业系统、行业标准(例如某些主数据同步、报文交换、配置导出)、甚至部分厂商的批量接口仍以 XML 为核心载体。对 ABAP Cloud 开发者来说,麻烦点在于:你既要把 XML 读懂、读稳,还要尽量使用 released 的 ABAP Cloud A…

mysql用户名怎么看

要查看 mysql 中的用户名&#xff0c;可以使用以下方法&#xff1a;使用 show databases 命令查看数据库拥有者信息&#xff1b;使用 ps 命令查看正在运行的 mysql 进程&#xff1b;使用 whoami 命令查看当前操作系统用户名&#xff1b;查看 /etc/mysql/my.cnf 或 /etc/my.cnf …

2026必备!9个AI论文写作软件,助研究生轻松搞定论文格式与内容!

2026必备&#xff01;9个AI论文写作软件&#xff0c;助研究生轻松搞定论文格式与内容&#xff01; AI 工具如何改变论文写作的未来 在当今快节奏的学术环境中&#xff0c;研究生们面对论文写作的压力日益增大。从选题到格式规范&#xff0c;再到内容撰写和降重&#xff0c;每一…

在 ABAP Cloud 里优雅地调用 HTTP 服务:新一代 HTTP Client 全面实践与落地指南

引言:当 ABAP 开始频繁对话 BTP,HTTP 就不再是配角 在很长一段时间里,SAP 系统的集成主力更多是 RFC、IDoc、SOAP 这类经典通道。HTTP 当然一直存在,CL_HTTP_CLIENT 也能搜到海量示例,但它往往只在少数场景里登场:比如调用某个外部 REST 服务、或者做一些轻量的技术验证…

MySQL迁移到达梦:如何轻松、高质量完成迁移任务

前言 由于业务需求要求数据库国产化&#xff0c;近期需要将数据从mysql数据库中迁移到达梦数据库中。本次使用达梦新的数据库开发和管理工具–SQLark百灵连接进行迁移&#xff0c;我也是在官方社区里看到大家推荐抱着试试看的心态去下载的。惊喜的是&#xff0c;五步即可快速搞…

ubuntu下的交叉编译

查看系统框架&#xff1a; uname -m # 查看系统 CPU 架构 PC端默认安装GCC&#xff1a; 是X86_x64架构的&#xff1b; 开发板安装GCC&#xff1a; 是arm架构的&#xff1b; 因此在PC端使用默认的GCC编译的执行文件无法在arm开发板内执行&#xff1b; 或者提示&#xff1a;“…

IDEA如何使用 Swing 构建用户界面

IntelliJ IDEA的 UI Designer插件使您可以使用 Swing 库组件为您的应用程序创建图形用户界面 (GUI)。 使用 UI Designer&#xff0c;您可以快速创建在顶层容器中使用的对话框和控件组&#xff0c;例如 JFrame。 这些元素可以与您直接在 Java 代码中定义的组件共存。 在本教程中…