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

设计模式——七大原则

​更多内容,前往 IT-BLOG

​设计模式的目的是为了让程序,具有更好的代码重用性、可读性(编程规范性,便于后期维护和理解)、可扩展性(当需要增加新需求时,非常方便)、可靠性(增加新功能后,对原功能么有影响)、使程序呈现高内聚,低耦合的特性。设计模式包含了面向对象的精髓,“懂了设计模式,就懂得了面向对象分析和设计(OOA/D)的核心”

一、单一职责原则

单一职责原则(SRP:Single responsibility principle)又称为单一功能原则: 它规定一个类应该只负责一项职责。

单一职责原则注意事项和细节:
1)、降低类的复杂度,一个类只负责一项职责。
2)、提高类的可读性,可维护性。
3)、降低变更引起的风险。
4)、通常情况下,我们应当遵守单一职责原则,只有当逻辑足够简单时,才可以在代码级别违反单一职责原则;只有类中方法足够少,可以在方法级别保持单一职责原则。

二、接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP)的定义: 客户端不应该依赖它不需要的接口类,类之间的依赖关系应该建立在最小的接口上。一句话,就是实现接口的类中,有多余的方法时,需要将接口进行拆分。

接口隔离原则的规范:
1)、使用接口隔离原则前首先需要满足单一职责原则。
2)、接口需要高内聚,也就是提高接口、类、模块的处理能力,少对外发布public的方法。
3)、定制服务,就是单独为一个个体提供优良的服务,简单来说就是拆分接口,对特定接口进行定制。
4)、接口设计是有限度的,接口的设计粒度越小,系统越灵活,但是值得注意不能过小,否则变成"字节码编程"。

接口隔离解决的问题如下(实现类实现了接口中不需要的抽象方法):

//接口
interface Interface1 {void operation1();void operation2();void operation3();
}class B implements Interface1 {public void operation1() {System.out.println("B 实现了 operation1");}public void operation2() {System.out.println("B 实现了 operation2");}public void operation3() {System.out.println("B 实现了 operation3");}
}
//问题所在:A类只用到了B类的 1,2 方法,但B类却要实现方法3,造成代码的冗余。
class A { //A 类通过接口Interface1 依赖(使用) B类,但是只会用到1,2方法public void depend1(Interface1 i) {i.operation1();}public void depend2(Interface1 i) {i.operation2();}
}

遵循接口隔离原则后(将抽象方法进行隔离,当需要时实现多个接口即可) :

// 接口1
interface Interface1 {void operation1();void operation2();
}// 接口2
interface Interface2 {void operation3();
}class B implements Interface1 {public void operation1() {System.out.println("B 实现了 operation1");}public void operation2() {System.out.println("B 实现了 operation2");}}class A { // A 类通过接口Interface1,Interface2 依赖(使用) B类,但是只会用到1,2,3方法public void depend1(Interface1 i) {i.operation1();}public void depend2(Interface2 i) {i.operation2();}
}

三、依赖倒置原则

依赖倒转原则(Dependency Inversion Principle,DIP)的定义: 程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

依赖倒置的原则:
1)、高层模块不应该依赖底层模块,二者都应该依赖其抽象。
2)、抽象不应该依赖细节(实现类),细节应该依赖抽象。
3)、依赖倒置的中心思想是面向接口编程。
4)、依赖倒置的的设计理念是:相对于细节的多样性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳的多。在 Java 中,抽象指的是接口和抽象类,细节就是具体的实现类。
5)、使用接口或抽象类的目的是定制好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

依赖倒置解决的问题如下(方法中传入的参数为类,而不是接口):

//完成 Person 接收消息的功能:这里receive方法中直接传入的对象是 类 也是依赖倒置重要强调的问题所在。
/**1. 如果我们获取的对象是 微信,短信等等,则新增类,同时Perons也要增加相应的接收方法getInfo()* 2. 解决思路:引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖* 因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就ok, 这样我们就符号依赖倒转原则*/
class Person {public void receive(Email email ) {System.out.println(email.getInfo());}
}class Email {public String getInfo() {return "电子邮件信息: hello,world";}
}

遵循依赖倒置原则后(方法中传入的参数修改为接口) :

public class DependecyInversion {public static void main(String[] args) {Person person = new Person();//当为电子邮件时,传入邮件对象person.receive(new Email());//当为微信时,传入微信对象person.receive(new WeiXin());}}//定义接口
interface IReceiver {public String getInfo();
}
//原电子邮件类,实现接口
class Email implements IReceiver {public String getInfo() {return "电子邮件信息: hello,world";}
}//增加微信
class WeiXin implements IReceiver {public String getInfo() {return "微信信息: hello,ok";}
}//方法中传入接口
class Person {//这里我们是对接口的依赖public void receive(IReceiver receiver ) {System.out.println(receiver.getInfo());}
}

依赖传递的三种方式和案例:
【1】接口传递: 就是上面举例的方式。
【2】构造方法传递:

//方式2: 通过构造方法依赖传递//接口1interface IOpenAndClose {public void open(); //抽象方法}//接口2interface ITV {public void play();}//接口1的方法实现调用接口2,接口2的实现通过构造器传入class OpenAndClose implements IOpenAndClose{//成员public ITV tv;//构造器public OpenAndClose(ITV tv){//将传入的对象值复制给自己的成员变量this.tv = tv;}//调用的方法public void open(){this.tv.play();}}//--------------测试类-------------------public class DependencyPass {public static void main(String[] args) {openAndClose.open(changHong);//通过构造器进行依赖传递OpenAndClose openAndClose = new OpenAndClose(changHong);openAndClose.open();}}

【3】setter 方法传递: (将实现类通过 set 方法传入到目标对象中):

// 方式3 , 通过setter方法传递
interface IOpenAndClose {public void open(); // 抽象方法//相当于多添加了一个方法,只用来获取实现 ITV 接口的实现类,并赋值给自己的属性对象。public void setTv(ITV tv);
}
// ITV接口
interface ITV {public void play();
}
//目标类(逻辑处理类)当tv属性多次使用到时,可以用此方法实现
class OpenAndClose implements IOpenAndClose {private ITV tv;public void setTv(ITV tv) {this.tv = tv;}public void open() {this.tv.play();}
}
//接口 ITV 的实现类
class ChangHong implements ITV {@Overridepublic void play() {System.out.println("长虹电视机,打开");}}
//--------------------测试-----------------
public class DependencyPass {public static void main(String[] args) {OpenAndClose openAndClose = new OpenAndClose();//通过setter方法进行依赖传递openAndClose.setTv(changHong);openAndClose.open();}
}

依赖倒置原则的注意事项和细节:
1)、低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好。
2)、变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲区层,对于程序扩展和优化。
3)、继承时遵循理氏替换原则

四、里氏替换原则

里氏代换原则(Liskov Substitution Principle,LSP)的定义: 所有引用基类的地方必须能透明地使用其子类的对象,子类可以扩展父类的功能,但不能改变父类原有的功能。面向对象(Object Oriented,OO)继承性的思考和说明:
1)、继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有子类都必须遵循这种契约,但是如果子类对这些已经实现的方法任意修改,就会对这个继承体系造成破坏。
2)、继承在给程序设计带来方便的同时,也带来了弊端。比如使用继承给程序带来侵入性,程序可移植性降低,增加对对象间的耦合性。如果一个类被其他的类所继承,则当此类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。
3)、问题提出:在编程中如何正确的使用继承,答案是:遵循里氏替换原则

里氏替换原则基本介绍:
1)、里氏替换原则是在1988年,有麻省理工学院的一名姓里的女士提出的。
2)、如果对类型为T1的对象o1,对有类型为T2的对象o2,使得以T1定义的所有程序P中对象o1可以代替成o2,程序 P 的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引用基类的地方能透明地使用其子类的对象。
3)、在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法。
4)、里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合、组合、依赖来解决问题。

里氏替换解决的问题如下:(子类重写了父类的方法)

// A类
class A {// 返回两个数的差public int func1(int num1, int num2) {return num1 - num2;}
}// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends A {//这里,重写了A类的方法, 可能是无意识public int func1(int a, int b) {return a + b;}public int func2(int a, int b) {return func1(a, b) + 9;}
}

遵循里氏替换原则后(提取一个公共的类,将A类与B类进行组合) :

//创建一个更加基础的基类
class Base {//把更加基础的方法和成员写到Base类
}// A类
class A extends Base {// 返回两个数的差public int func1(int num1, int num2) {return num1 - num2;}
}// B类继承了A
// 增加了一个新功能:完成两个数相加,然后和9求和
class B extends Base {//如果B需要使用A类的方法,使用组合关系private A a = new A();//这里,重写了A类的方法, 可能是无意识public int func1(int a, int b) {return a + b;}public int func2(int a, int b) {return func1(a, b) + 9;}//我们仍然想使用A的方法public int func3(int a, int b) {return this.a.func1(a, b);}
}

五、开闭原则

开闭原则(Open Closed Principle,OCP)的定义是: 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。模块应尽量在不修改原代码的情况下进行扩展。

开闭原则的基本介绍:
1)、开闭原则是编程中最基础、最重要的设计原则。
2)、一个软件实体,如类,模块和函数应该对扩展开发(提供方),对修改关闭(使用方)。用抽象构建框架,用实现扩展细节。
3)、当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是修改已有的代码来实现变化。
4)、编程中遵循其他原则,以及使用设计模式的目的就是遵循开闭原则

开闭原则解决的问题如下:(在使用方进行了代码修改)

//这是一个用于绘图的类 [使用方]
class GraphicEditor {//接收Shape对象,然后根据type,来绘制不同的图形public void drawShape(Shape s) {//**问题所在:此类属于使用方,但当我们需要扩展新的图形时,却要修改使用方,就不符合OCP原则if (s.m_type == 1) {drawRectangle(s);}else if (s.m_type == 2) {drawCircle(s);}}//绘制矩形public void drawRectangle(Shape r) {System.out.println(" 绘制矩形 ");}//绘制圆形public void drawCircle(Shape r) {System.out.println(" 绘制圆形 ");}
}//Shape类,基类
class Shape {int m_type;
}class Rectangle extends Shape {Rectangle() {super.m_type = 1;}
}
class Circle extends Shape {Circle() {super.m_type = 2;}
}

遵循开闭替换原则(将公共方法提取到抽象类,在实现类中实现需要调用的方法,使用类中直接调用公共方法即可) :

//这是一个用于绘图的类 [使用方]
class GraphicEditor {//接收Shape对象,调用draw方法public void drawShape(Shape s) {//直接调用公共方法即可,就算增加新的图形也无需修改此处,//当多个地方调用时,更能体现OCP的重要性,这里只是简单举例s.draw();}
}//Shape类,基类
abstract class Shape {//抽象方法public abstract void draw();
}
//[提供方]
class Rectangle extends Shape {@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println(" 绘制矩形 ");}
}class Circle extends Shape {@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println(" 绘制圆形 ");}
}

六、迪米特法则

迪米特法则(Law of Demeter,LOD),有时候也叫做最少知识原则(Least Knowledge Principle,LKP)定义是: 一个软件实体应尽可能少地与其他实体发生相互作用。迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块独立,相互之间不存在(或很少有)依赖关系。迪米特法则则不希望类之间建立直接的关系。如果真的有需要建立联系,也希望能通过它的友元类(中间类或者跳转类)来转达。

迪米特法则的规则:
1)、Only talk to your immediate friends(只与直接的朋友通讯):每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系, 我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友(例如,在一个方法中new了一个类,那么此类就不属于直接朋友)。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。
2)、一个对象应该对其他对象保持最少的了解。
3)、类与类关系越密切,耦合度越大。
4)、迪米特法则指一个类对自己依赖的类知道的 越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public 方法,不对外泄露任何信息。
5)、 迪米特法则还有个更简单的定义:只与直接的朋友通信。

迪米特法则解决的问题如下: (方法中出现了局部变量)

//通过查看如下代码会发现,CollegeEmployee 以局部变量的形式出现在方法 printAllEmployee 中,违反了迪米特法则
public class Demeter1 {//该方法完成输出学校总部和学院员工信息(id)void printAllEmployee(CollegeManager sub) {//分析问题//1. 这里的 CollegeEmployee 不是  SchoolManager的直接朋友//2. CollegeEmployee 是以局部变量方式出现在 SchoolManager//3. 违反了 迪米特法则//获取到学院员工List<CollegeEmployee> list1 = sub.getAllEmployee();System.out.println("------------学院员工------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}}

遵循迪米特法则后(将局部变量部分,提取到自己的类中):

public class DemeterUpdate {void printAllEmployee(CollegeManager sub) {//分析问题//1. 将输出学院的员工方法,封装到CollegeManagersub.printEmployee();}
}//管理学院员工的管理类
class CollegeManager {//输出学院员工的信息public void printEmployee() {//获取到学院员工List<CollegeEmployee> list1 = getAllEmployee();System.out.println("------------学院员工------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}}//返回学院的所有员工public List<CollegeEmployee> getAllEmployee() {List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 listCollegeEmployee emp = new CollegeEmployee();emp.setId("学院员工id= " + i);list.add(emp);}return list;}
}

迪米特法则注意事项和细节:
1)、迪米特法则的核心是降低类之间的耦合。
2)、但是注意:由于每个类之间都减少了不必要的依赖,因此迪米特法则只是要求降低类之间(对象间)耦合关系,并不是要求完全没有依赖关系。

七、合成复用原则

合成复用原则的定义是: 原则是尽量使用合成/聚合的方法,而不是使用继承。
聚合用来表示“拥有”关系或者整体与部分的关系: 代表部分的对象有可能会被多个代表整体的对象所共享,而且不一定会随着某个代表整体的对象被销毁或破坏而被销毁或破坏,部分的生命周期可以超越整体。例如,班级和学生,当班级删除后,学生还能存在,学生可以被培训机构引用。

class OpenAndClose implements IOpenAndClose {private ITV tv;//通过set方法将ITV对象聚合到OpenAndClose对象中public void setTv(ITV tv) {this.tv = tv;}public void open() {this.tv.play();}
}

合成用来表示一种强得多的“拥有”关系: 在一个合成关系里,部分和整体的生命周期是一样的。一个合成的新对象完全拥有对其组成部分的支配权,包括它们的创建和湮灭等。使用程序语言的术语来说,合成的新对象对组成部分的内存分配、内存释放有绝对的责任。例如,一个人由头、四肢和各种器官组成,人与这些具有相同的生命周期,人死了,这些器官也就挂了。房子和房间的关系,当房子没了,房间也不可能独立存在。

class OpenAndClose implements IOpenAndClose {//将 ITV 对象组合到 OpenAndClose 对象中ITV tv = new ITV();
}

【总结】设计原则的核心思想:
【1】找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
【2】 针对接口编程,而不是针对实现编程。
【3】为了交互对象之间的松耦合设计而努力。

简单理解就是: 开闭原则是总纲,它指导我们要对扩展开放,对修改关闭;单一职责原则指导我们实现类要职责单一;里氏替换原则指导我们不要破坏继承体系;依赖倒置原则指导我们要面向接口编程;接口隔离原则指导我们在设计接口的时候要精简单一;迪米特法则指导我们要降低耦合。

设计模式就是通过这七个原则,来指导我们如何做一个好的设计。但是设计模式不是一套“奇技淫巧”,它是一套方法论,一种高内聚、低耦合的设计思想。我们可以在此基础上自由的发挥,甚至设计出自己的一套设计模式。

当然,学习设计模式或者是在工程中实践设计模式,必须深入到某一个特定的业务场景中去,再结合对业务场景的理解和领域模型的建立,才能体会到设计模式思想的精髓。如果脱离具体的业务逻辑去学习或者使用设计模式,那是极其空洞的。

相关文章:

设计模式——七大原则

​更多内容&#xff0c;前往 IT-BLOG ​设计模式的目的是为了让程序&#xff0c;具有更好的代码重用性、可读性&#xff08;编程规范性&#xff0c;便于后期维护和理解&#xff09;、可扩展性&#xff08;当需要增加新需求时&#xff0c;非常方便&#xff09;、可靠性&#xf…...

笔记本电脑的WIFI模块,突然不显示了,网络也连接不上

问题复现&#xff1a; 早上&#xff0c;在更新完笔记本电脑的系统之后&#xff0c;连网之后&#xff0c;网络突然直接断开&#xff0c;一查看&#xff0c;WiFi模块居然不见了&#xff0c;开机重启也是如此&#xff0c;这种情况常常出现在更新系统之后&#xff0c;WiFi模块驱动就…...

Pytest 与allure测试报告集成

通过Feature, story, step 记录测试的功能&#xff0c;场景及测试步骤 # login.pylogin_func函数 传入参数是name 和 password 当输入的name和password与数据库db_data中数据一致时&#xff0c;返回“XXX成功登录系统&#xff01;” 当输入的name存在于数据库db_data但密码不正…...

MySQL 表的增删改查(基础)

1.CRUD 注释:在SQL中可以使用"--空格描述"来表示注释说明 CRUD 即增加(Create).查询(Retrieve).更新(Update).删除(Delete) 2.新增(Create) insert into 表名 values (列,列...); insert into 表名(列名,列名...) values (列,列...); insert into 表名 values(),(),…...

【PDF.js】发票PDF不显示文本的问题

控制台提示警告&#xff1a; Warning: loadFont - translateFont failed: "UnknownErrorException: The CMap "baseUrl" parameter must be specified, ensure that the "cMapUrl" and "cMapPacked" API parameters are provided.".…...

C#中检查空值的最佳实践

C#中检查空值的最佳实践 在C#编程中&#xff0c;处理空值是一项基础且重要的任务。正确地检查变量是否为null可以帮助我们避免NullReferenceException&#xff0c;这是C#最常见的运行时错误之一。本文将探讨为什么使用is关键字进行空值检查是一种优于使用的做法。 操作符&…...

三层交换组网实验(华为)

思科设备参考&#xff1a;三层交换组网实验&#xff08;思科&#xff09; 一&#xff0c;技术简介 三层交换技术的出现&#xff0c;解决子网必须依赖路由器进行管理的问题&#xff0c;解决传统路由器低速、复杂所造成的网络瓶颈问题。一个具有三层交换功能的设备可简单理解为…...

Android配置GitLab CI/CD持续集成,Shell版本的gitlab-runner,FastLane执行,上传蒲公英

mac环境下&#xff0c; 首选需要安装gitlab-runner和fastlane brew install gitlab-runner brew install fastlane 安装完成&#xff0c;来到我们在gitlab下新建的Android项目&#xff0c;我们开始创建gitlab-runner 1、创建runner 点开runner&#xff0c;点击新建runner …...

算法提升——LeetCode383场周赛总结

周赛题目 边界上的蚂蚁 边界上有一只蚂蚁&#xff0c;它有时向左走&#xff0c;有时向右走。 给你一个非零整数数组nums。蚂蚁会按顺序读取nums中的元素&#xff0c;从第一个元素开始直到结束。每一步&#xff0c;蚂蚁会根据当前元素的值移动&#xff1a; 如果nums[i]<0…...

(delphi11最新学习资料) Object Pascal 学习笔记---第4章第2.1节( 带结果的Exit例程)

4.2.1 带结果的Exit例程 ​ 我们已经看到&#xff0c;从函数中返回结果所使用的语法与 C 语言家族的语法截然不同。不仅语法不同&#xff0c;行为也不同。为结果&#xff08;或函数名&#xff09;赋值并不像return语句那样终止函数。Object Pascal 开发人员经常利用这一特性&a…...

vuecli3 执行 npm run build 打包命令报错:TypeError: file.split is not a function

问题 今天有个项目在打包的时候遇到了一个问题&#xff0c;就是执行 npm run build 命令的时候报错了&#xff0c;如下&#xff1a; 解决 我排查了一下&#xff0c;模拟代码如下&#xff1a;在打包的时候用了 MinChunkSizePlugin const webpack require("webpack"…...

【Java 数据结构】对象的比较

Java中对象的比较 1. PriorityQueue中插入对象2. 元素的比较2.1 基本类型的比较2.2 对象比较的问题 3. 对象的比较3.1 覆写基类的equals3.2 基于Comparble接口类的比较3.3 基于比较器比较3.4 三种方式对比 4. 集合框架中PriorityQueue的比较方式5. 使用PriorityQueue创建大小堆…...

2024 Google Chrome 浏览器回退安装旧版本

2024 Google Chrome 浏览器回退安装旧版本 查看当前谷歌版本备份浏览器数据卸载浏览器双击重新安装旧版本浏览器 查看当前谷歌版本 详细参考&#xff1a;参考 笔记&#xff1a;最近谷歌浏览器更新后&#xff0c;用着总感觉别扭&#xff1a;不习惯 备份浏览器数据 &#xff…...

将数组中的各字符串都调整为指定长度调整原则:多删(删右侧多出的)少补(左侧补数字0)numpy.char.zfill()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 将数组中的各字符串 都调整为指定长度 调整原则&#xff1a; 多删&#xff08;删右侧多出的&#xff09; 少补&#xff08;左侧补数字0&#xff09; numpy.char.zfill() [太阳]选择题 请问以…...

算法题目题单——图论

简介 本文为自己做的一部分图论题目&#xff0c;作为题单列出&#xff0c;持续更新。 题单由题目链接和题解两部分组成&#xff0c;题解部分提供简洁题意&#xff0c;代码仓库&#xff1a;Kaiser-Yang/OJProblems。 对于同一个一级标题下的题目&#xff0c;题目难度尽可能做…...

Maven提示Failure to find com.oracle:ojdbc14:jar:10.2.0.4.0

目录 问题 解决方案 1、下载oracle的驱动jar包 2、安装到本地仓库 3、检查本地仓库是否成功安装 4、Maven先clean &#xff0c;再install。 问题 项目引入Oracle依赖后报错&#xff0c;显示为红色。 解决方案 1、下载oracle的驱动jar包 首先我们要去下载一个oracle的…...

深度学习的数据集制作、标注、处理相关软件

制作深度学习数据集通常涉及数据的采集、标注和预处理等步骤。以下是一些可用于制作和处理深度学习数据集的软件工具&#xff0c;以及它们的详细介绍&#xff1a; 数据采集和生成 Web爬虫工具 (如 Scrapy, Beautiful Soup) 描述&#xff1a;这些工具可以帮助你从网上自动抓取和…...

点击按钮打开自定义iframe弹窗

1、效果 点击按钮打开弹窗&#xff1a; 打开弹窗后&#xff1a; 2、代码 <!DOCTYPE html> <html><head><title>iframe弹窗</title><style>/* 使用媒体查询来实现响应式设计 */media (min-width: 768px) {.popup {width: 80%; /* 设置…...

LeetCode977 有序数组的平方

暴力解法是平方之后排序复杂度是nnlogn 优化解法是双指针i&#xff0c;j&#xff0c;i放数组首元素位置&#xff0c;j放数组末尾&#xff0c;每次比较i和j位置的数组元素大小&#xff0c;然后挑一个大的放在新的数组元素的指定末尾位置上。 当原始数组nums第一个元素大于零时&a…...

Windows自动化实现:系统通知和任务栏图标自定义

文章目录 Windows自动化的三个小工具系统通知任务栏图标使用pystray实现使用infi.systray实现 Windows自动化的三个小工具 系统通知 import win10toastwin10toast.ToastNotifier().show_toast("eee", "休息一下", icon_path"icon.ico", durati…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...