设计模式之六大设计原则
文章目录
- 高内聚低耦合
- 设计原则
- 开闭原则
- 单一职责原则
- 里氏代换原则
- 依赖倒置原则
- 迪米特原则
- 接口隔离原则
高内聚低耦合
提高代码的可读性、可维护性和可扩展性,降低开发和维护的成本,并减少系统的风险
内聚:
内聚表示一个模块内部各个元素之间相互关联的程度。
高内聚意味着模块内部的功能紧密相关,所有部分都共同完成一个特定的任务或功能。
低内聚则意味着模块内部包含多种不相关的功能。
耦合:
耦合表示不同模块之间相互依赖的程度。
高耦合意味着模块之间相互依赖紧密,一个模块的变化会影响到其他模块。
低耦合则意味着模块之间相对独立,一个模块的变化对其他模块的影响较小。
举个例子:
汽车是由许多不同的部件组成的,比如发动机、轮胎、刹车等等。
在高内聚低耦合的设计中,每个部件都应该专注于自己的功能,同时尽可能减少与其他部件之间的依赖关系。
高内聚意味着每个部件都应该有一个清晰的责任和功能。发动机的责任是提供动力,而刹车系统的责任是提供制动。这样设计的好处是,每个部件都可以独立工作,而不需要过多依赖其他部件的内部细节。
低耦合意味着部件之间的相互依赖应该尽可能减少。刹车系统不需要知道发动机如何工作,它只需要知道何时需要制动。这样设计的好处是,如果需要更改或替换一个部件,不会对其他部件产生太大影响,因为它们之间的依赖关系很少。
高内聚:意味着一个类或模块的内部元素(包括变量、方法和属性)应该紧密相关,并且共同服务于一个明确且集中的目的。
低耦合:模块或类之间的依赖关系应该尽可能少
- 内紧(高内聚):程序内的模块或类应该紧密相关,形成一个高效的功能单元。
- 外松(低耦合):程序之间的模块或类应该尽可能不关联,各自实现各自的功能。
设计原则
在进行软件系统设计时所要遵循的一些经验准则,应用该准则的目的通常是为了避免某些经常出现的设计缺陷,提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性
包括单一职责原则,开放封闭原则,里氏替换原则,依赖倒置原则,迪米特原则,接口隔离原则
开闭原则
(Open-Closed Principle, OCP)
定义:类,模块,函数等应该是可以拓展的,但是不可修改
对扩展开放,对修改关闭。
我们需要使用抽象实现(接口和抽象类)达到这样的效果。
因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。
而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
举个例子
//AbstractSkin.java
public abstract class AbstractSkin {//显示皮肤public abstract void display();
}//DefaultSkin.java
public class DefaultSkin extends AbstractSkin{@Overridepublic void display() {System.out.println("默认皮肤");}
}//WhiteSkin.java
public class WhiteSkin extends AbstractSkin{@Overridepublic void display() {System.out.println("白色皮肤");}
}//SougouInput.java
public class SougouInput {private AbstractSkin skin;public AbstractSkin getSkin() {return skin;}//通过setSkin方法设置不同的皮肤实现public void setSkin(AbstractSkin skin) {this.skin = skin;}public void display() {skin.display();}
}//Client.java
public class Client {public static void main(String[] args) {//1.创建输入法对象SougouInput input = new SougouInput();//2.创建皮肤对象DefaultSkin skin = new DefaultSkin();//WhiteSkin skin = new WhiteSkin();//3.将皮肤设置到输入法中input.setSkin(skin);//4.显示皮肤input.display();}
}
SougouInput 类通过其 setSkin 方法允许添加不同类型的皮肤(如 DefaultSkin 或 WhiteSkin),这体现了对扩展的开放性。
由于 SougouInput 类依赖于 AbstractSkin 抽象类而不是具体的皮肤实现类,因此添加新的皮肤类型只需要创建新的子类并实现 AbstractSkin 的 display 方法,而不需要修改 SougouInput 类的代码。这体现了对修改的封闭性。
皮肤的类不用修改,再创建新皮肤,让他继承AbstractSkin抽象类,在客户端类代码进行修改即可。
作用:
- 提高软件的可维护性
- 增强软件的扩展性
- 减少代码的耦合度
单一职责原则
(Single Responsibility Principle,SRP)
定义:一个类(或模块、函数等)应该只有一个引起它变化的原因。换句话说,一个类应该只负责一个功能领域中的相关职责,或者变化的原因应该只有一个。
下面是不符合单一职责原则的例子:
public class TelPhone {public void Dial(String phone_number){System.out.println("给"+phone_number+"打电话");}public void HangUp(String phone_number) {System.out.println("挂断" + phone_number + "打电话");}public void SendMessage(String message) {System.out.println("发送" + message);}public void ReceiveMessage(String message) {System.out.println("接收" + message);}
}
可能发生的变化:
-
内部的变化,如果
TelPhone类中的任何一个方法发生改变,,都需要修改TeIPhone、由于它负责了多个职责,所以一个职责的变化可能会导致其他无关职责的代码也需要被修改或重新测试。 -
外部的变化,如果
TeIPhone要添加新的的方法,需要修改TeIPhone类
为了符合单一职责原则,我们可以做出如下修改:
但中间的依然不符合,存在一个以上引起类变化的原因,所以我们可以考虑最右边的,一个类中只有一个方法

但这样比较极端,会导致类的数量大幅增加,使得管理和维护代码变得复杂。
因此,我们通常要在单一职责原则和实际应用之间找到一个平衡点。
实现方式:
给每个方法,都提炼成一个接口,抽象成一种能力,然后分别写类,去实现接口,最终在TelPhone中只进行调用。
package com.feng.test01;interface Dialer {void Dial(String phoneNumber);
}interface Hanger {void HangUp();
}interface Sender {void SendMessage(String text);
}interface Receiver {void ReciveMessage(String text);
}class DialerImpl implements Dialer {public void Dial(String phoneNumber) {System.out.println("给 " + phoneNumber + " 打电话");}
}class HangerImpl implements Hanger {public void HangUp() {System.out.println("挂断电话");}
}class SenderImpl implements Sender {public void SendMessage(String text) {System.out.println("发送 " + text);}
}class ReceiverImpl implements Receiver {public void ReciveMessage(String text) {System.out.println("接收 " + text);}
}class TelPhone {private Dialer dialer;private Hanger hanger;private Sender sender;private Receiver receiver;public TelPhone(Dialer dialer, Hanger hanger, Sender sender, Receiver receiver) {this.dialer = dialer;this.hanger = hanger;this.sender = sender;this.receiver = receiver;}public void Dial(String phoneNumber) {dialer.Dial(phoneNumber);}public void HangUp() {hanger.HangUp();}public void SendMessage(String text) {sender.SendMessage(text);}public void ReciveMessage(String text) {receiver.ReciveMessage(text);}
}public class Main {public static void main(String[] args) {// 创建接口实现类实例Dialer dialer = new DialerImpl();Hanger hanger = new HangerImpl();Sender sender = new SenderImpl();Receiver receiver = new ReceiverImpl();// 创建 TelPhone 对象并使用其接口TelPhone telphone = new TelPhone(dialer, hanger, sender, receiver);// 电话呼叫操作telphone.Dial("123456789");telphone.HangUp();// 消息操作telphone.SendMessage("Hello, World!");telphone.ReciveMessage("Hi there!");}
}
好处:
- 提高代码的可读性,提高系统的可维护性。
- 降低类的复杂性,一个模块只负责一个职责,提高系统的可扩展性和可维护性。
- 降低变更引起的风险。变更是不然的,如果单一职责做得好,当修改一个功能的时候可以显著的降低对另一个功能的影响。
里氏代换原则
(Liskov Substitution Principle,LSP)
里氏代换原则:任何基类可以出现的地方,子类一定可以出现。
通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。
要点:
功能保持:子类应当能够替代基类,并且子类对象应能代替基类对象使用,而不会导致程序运行出现问题。
行为一致:子类可以扩展基类的功能,但不能改变基类的功能。即子类的行为应该与基类保持一致
要求:
- 子类可以实现父类的抽象方法,但不要去覆盖(重写)父类的非抽象方法
- 子类可以增加自己特有的方法
- 当子类的方法重写父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松
- 当子类的方法实现父类的方法时(重写或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或与父类一样
package com.feng.test05;public abstract class Coder {public void coding() {System.out.println("我会敲代码!");}
}class JavaCoder extends Coder {public void play() {System.out.println("喜欢玩XXXX");}//重写了父类的非抽象方法public void coding() {System.out.println("我只会敲JAVA代码!");}
}
里氏代换原则指出,如果程序中的对象使用的是基类(父类)的话,那么无论是使用基类对象还是其子类对象,程序的行为都是一致的。
用 JavaCoder 替代 Coder 时,本来会敲很多代码,但现在只会敲JAVA了。
所以尽量不要去重写父类非抽象方法,不要改变父类原有的功能。
可以这样修改:
- 保留父类方法的行为,并且扩展子类方法的功能
public void coding() {super.coding(); // 调用父类的coding方法System.out.println("我会敲JAVA代码!");}
- 或者再写一个
javaCoding方法 - 写
JavaCoder和Coder的抽象父类People,把coding这一行为定义在People中,放弃JavaCoder和Coder的继承关系
好处:
- 开放性:是实现开放封闭原则的的具体手段之一
- 提高代码的可复用性
依赖倒置原则
(Dependence Inversion Principle,DIP)
定义:高层模块不应该依赖低层模块,两者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。
旨在通过依赖于抽象而不是具体实现来降低系统的耦合度,提高系统的可维护性和可扩展性。
下面是一个违背依赖倒置原则的例子
package com.feng.test04;class FuelCar{public void run(){System.out.println("开的是燃油车");}
}class Driver{public void drive(FuelCar car) {car.run();}
}public class Client {public static void main(String[] args) {FuelCar fuelCar = new FuelCar();Driver xiaowang = new Driver();xiaowang.drive(fuelCar);}
}
Driver 类直接依赖于 FuelCar 类,而没有使用抽象,违反了依赖倒置原则。
如果我们想要支持其他类型的车辆,比如电动车或者公交车,就需要修改 Driver 类,这样会增加代码的耦合度和维护成本。
高层模块(Driver)不应该直接依赖于低层模块(FuelCar),而是应该依赖于抽象。在这个例子中,Driver 类应该依赖于一个抽象的 ICar 接口,而不是具体的 FuelCar 类。
我们可以引入一个接口来表示所有类型的车,并让FuelCar实现这个接口。然后,Driver的drive方法可以接受任何实现了ICar接口的对象作为参数。
package com.feng.test04after;interface ICar {void run();
}class FuelICar implements ICar {@Overridepublic void run() {System.out.println("开的是燃油车");}
}class ElectricICar implements ICar {@Overridepublic void run() {System.out.println("开的是电车");}
}class Driver {public void drive(ICar car) {car.run();}
}public class Client {public static void main(String[] args) {ICar su7 = new ElectricICar();ICar benz = new FuelICar();Driver driver = new Driver();driver.drive(su7);driver.drive(benz);}
}
作用:
- 提高代码的可维护性
- 降低代码的耦合度
- 提高系统的可扩展性
迪米特原则
(Law of Demeter,LoD)
也称为最少知识原则:一个对象应该对其他对象有最少的了解。
定义:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用
一个对象应该对其他对象知之甚少,只与“朋友”通信,而不与“陌生人”直接通信。
- 租房者-中介-房东
- 要做软件的公司-软件公司-软件工程师
这里的“朋友”指的是当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等
这些对象同当前对象存在关联、依赖、聚合或组合关系,可以直接访问这些对象的方法。
下面是一个
import java.util.ArrayList;
import java.util.List;class Product {private String name;private double price;public Product(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;}
}// 购物车类
class ShoppingCart {private List<Product> products;public ShoppingCart() {this.products = new ArrayList<>();}// 添加商品到购物车public void addProduct(Product product) {products.add(product);}// 打印购物车中的商品信息public void printCart() {for (Product product : products) {System.out.println("商品:" + product.getName() + " 价格:" + product.getPrice());}}
}public class Test {public static void main(String[] args) {Product product1 = new Product("banana", 2);Product product2 = new Product("apple", 5);ShoppingCart cart = new ShoppingCart();cart.addProduct(product1);cart.addProduct(product2);cart.printCart();}
}
ShoppingCart 类对 Product 类的了解仅限于 getName 和 getPrice 方法,这是符合迪米特原则的。ShoppingCart 不需要知道 Product 类的内部实现细节,也不需要与其他任何与 Product 类相关的“陌生人”对象进行交互。
好处:
- 降低耦合性
- 提高模块独立性
- 增强系统的可维护性
接口隔离原则
(Interface Segregation Principle,ISP)
定义:一个类对另一个类的依赖应该建立在最小的接口上。
建立单一接口,不要建立庞大臃肿的接口;尽量细化接口,接口中的方法尽量少。
也就是说,我们要为各个类建立专用的接口,而不要试图建立一个很庞大的接口件所有依赖它的类通用。
下面是一个不符合接口隔离原则的例子:
package com.feng.test03;interface Device {String getCpu();String getType();String getMemory();
}
class computer implements Device{@Overridepublic String getCpu() {return "i7";}@Overridepublic String getType() {return "笔记本电脑";}@Overridepublic String getMemory() {return "16GB";}
}class fan implements Device{@Overridepublic String getCpu() {return null; //不需要的方法}@Overridepublic String getType() {return "电风扇";}@Overridepublic String getMemory() {return null; //不需要的方法}
}
虽然定义了一个Device接口,但是由于此接口的粒度不够细化,类依赖于不需要的方法。虽然比较契合电脑这种设备,但是不适合风扇,要对其进行更细粒度的划分。
接口的粒度:描述了接口所提供功能的大小和复杂度
下面是一个符合接口隔离原则粒度更细的代码:
// 通用设备接口
interface GenericDevice { String getType();
} // 电脑设备接口
interface ComputerDevice extends GenericDevice { String getCpu(); String getMemory();
} // 风扇设备接口
interface FanDevice extends GenericDevice {void adjustSpeed(int speed);
}
注意:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计的灵活性;但是如果过小,则会造成接口数量过多,使设计复杂化。所以,接口的大小一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类需要的方法,不需要的方法则隐藏起来只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
- 提高内聚,减少对外交互。接口方法尽量少用
public修饰。接口是对外的承诺,承诺越少,对系统的开发越有利,变更风险也会越少。
作用:
- 降低耦合性
- 提高灵活性
- 增强可维护性
- 开闭原则:抽象架构,扩展实现
- 单一职责:一个类和方法只做一件事
- 里氏替换: 多态,子类可扩展父类
- 依赖倒置:细节依赖抽象,下层依赖上层
- 接口隔离:建立单一接口
- 迪米特原则:最少知道,降低耦合
参考:
- 14.设计模式-设计原则(依赖倒转原则概述和案例)
- 【设计模式】六大原则详解
- 六大设计原则超详细介绍
- 面向对象设计原则
如有错误烦请指正。
感谢您的阅读
相关文章:
设计模式之六大设计原则
文章目录 高内聚低耦合设计原则开闭原则单一职责原则里氏代换原则依赖倒置原则迪米特原则接口隔离原则 高内聚低耦合 提高代码的可读性、可维护性和可扩展性,降低开发和维护的成本,并减少系统的风险 内聚: 内聚表示一个模块内部各个元素之间…...
【iOS】UI学习(一)
UI学习(一) UILabelUIButtonUIButton事件 UIViewUIView对象的隐藏UIView的层级关系 UIWindowUIViewController定时器与视图对象 UISwitch UILabel UILabel是一种可以显示在屏幕上,显示文字的一种UI。 下面使用代码来演示UILabel的功能&#…...
如何使用Vue和Markdown实现博客功能
创建Vue项目和安装依赖 npm install -g @vue/cli vue create vue-blog cd vue-blog npm install vue-markdown-loader --save-dev配置Vue项目以解析Markdown 在 vue.config.js 文件中添加以下配置: module.exports = {chainWebpack: config => {config...
1初识C#
1、Console安慰 Console.WriteLine("Hello, world!"); // 输出 "Hello, world!" 并换行 Console.WriteLine(123.45); // 输出数字 123.45 并换行 Console.WriteLine("Name: " name); // 输出 "Name: [变量name的值]" 并换行 2、 C…...
查询指定会话免打扰
查询指定用户(requestId) 为指定会话(targetId)的设置的免打扰状态。 提示 该设置为用户级别设置。对应的设置接口详见设置指定会话免打扰。 请求方法 POST: https://数据中心域名/conversation/notification/get.json 频率限…...
Linux-命令
添加权限方法及注意事项: 字母权限法很灵活,无论目录还是文件都可以随意添加删除超级权限 chmod us ... 添加SUID chmod gs ... 添加SGID chmod s ...同时添加SUID和SGID chmod -s ...同时删除SUID和SGID chmod ot ...添加Sticky chmod t ...同上 数字权限表示法添加/删除…...
STM32读写内部FLASH读取芯片id
文章目录 读写内部Flash接线程序编写测试效果补充 读取芯片id代码编写 读写内部Flash 接线 程序编写 首先使用ThisFlash.c来写入flash的基本操作,写入、读取、擦除,然后使用Store.c配合数组来进行主存与flash的交互 ThisFlash.c #include "stm32…...
前端npm打包及报错解决
前端npm install 安装node 下载地址 https://nodejs.org/en/download/prebuilt-binaries 配置环境变量 wget https://nodejs.org/dist/v14.21.3/node-v14.21.3-linux-x64.tar.xz tar xf node-v14.21.3-linux-x64.tar.xz -C /data/ vim /etc/profile export NODE_HOME/data/n…...
vbs执行报错vbs没有文件拓展,双击无法打开
如果看不到文件扩展名需要设置: 无法双击打开vbs 一般为注册表问题 解决办法 将下方代码保存为xxx.reg Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.VBS] "VBSFile" [HKEY_CLASSES_ROOT.VBS\PersistentHandler] "{5e941d80-bf96-…...
超详细的前后端实战项目(Spring系列加上vue3)前端篇(二)(一步步实现+源码)
好了,兄弟们,继昨天的项目之后,开始继续敲前端代码,完成前端部分 昨天完成了全局页面的代码,和登录页面的代码,不过昨天的代码还有一些需要补充的,这里添加一下 内容补充:在调用登…...
【国产中颖】SH79F9202U单片机驱动LCD段码液晶学习笔记
1. 引言 因新公司之前液晶数显表产品单片机一直用的是 C51单片机(SH79F9202U9),本人之前没有接触过这款单片机,为了维护老产品不得不重新研究研究这款单片机。 10位ADC LCD的增强型8051微控制器 SH79F9202是一种高速高效率8051可兼容单片机。在同样振…...
人工智能初识
🌞欢迎来到人工智能基础的世界 🌈博客主页:卿云阁 💌欢迎关注🎉点赞👍收藏⭐️留言📝 🌟本文由卿云阁原创! 📆首发时间:🌹2024年5月1…...
【算法刷题day60】Leetcode:84. 柱状图中最大的矩形
文章目录 Leetcode 84. 柱状图中最大的矩形解题思路代码总结 草稿图网站 java的Deque Leetcode 84. 柱状图中最大的矩形 题目:84. 柱状图中最大的矩形 解析:代码随想录解析 解题思路 反方向接雨水。见上一篇文章 代码 class Solution {public int la…...
ThingsBoard物联网网关在智慧城市数据采集中的应用
智慧城市由监控中心、采集网关、前端采集设备、前端感应执行器组成。 为何选用ThingsBoard作为平台 监控中心为物联网平台,该平台包含云计算、大数据、人工智能、物联网、GIS、云安全等主要模块,具备数据采集、数据交换、超大规模计算、数据分析、数据应…...
Java中的打印流PrintStream 和 PrintWriter
PrintStream和PrintWriter在Java中都是用于打印输出的类,但它们之间存在一些明显的区别。以下是关于这两个类的详细解释和比较: PrintStream 基本特性 PrintStream是一个字节打印流,它继承自FilterOutputStream。 主要操作byte流࿰…...
【MATLAB源码-第217期】基于matlab的16QAM系统相位偏移估计HOS算法仿真,对比补偿前后的星座图误码率。
操作环境: MATLAB 2022a 1、算法描述 高阶统计量(HOS)频偏估计算法 高阶统计量(Higher Order Statistics, HOS)频偏估计算法是一种先进的信号处理技术,广泛应用于现代数字通信系统中,以应对…...
C# CryptoStream流的详解与示例
在当今数字时代,数据安全变得越来越重要。保护敏感信息免受未授权访问是每个开发者的责任。在C#中,使用CryptoStream流可以方便地对数据进行加密和解密。本文将详细介绍C# CryptoStream库的用法、功能以及它如何对数据进行加密和解密。 一、CryptoStrea…...
Kubernetes 之 ReplicaSet
Kubernetes 之 ReplicaSet ReplicaSet 定义 ReplicaSet 是 Kubernetes 中的一种副本控制器,其主要作用是控制其管理的 Pod 的预设副本数量。它会持续监听这些 Pod 的运行状态,在Pod发生故障时执行重启策略,当 Pod 数量减少时会重新启动新的…...
转发和重定向
目录 是什么 转发(Forwarding) 概念 特点 实现方式 重定向(Redirecting) 概念 特点 实现方式 转发和重定向区别整理 转发和重定向的适用场景 转发(Forwarding) 重定向(Redirect&am…...
源码部署ELK
目录 资源列表 基础环境 关闭防护墙 关闭内核安全机制 修改主机名 添加hosts映射 一、部署elasticsearch 修改limit限制 部署elasticsearch 修改配置文件 单节点 集群(3台节点集群为例) 启动 二、部署logstash 部署logstash 添加配置文件 启动 三、部署kiban…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
