java设计模式(2)---六大原则
设计模式之六大原则
这篇博客非常有意义,希望自己能够理解的基础上,在实际开发中融入这些思想,运用里面的精髓。
先列出六大原则:单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特原则、开闭原则。
一、单一职责原则
1、单一职责定义
单一职责原则:一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
单一职责原则告诉我们:一个类不能太“累”!在软件系统中,一个类承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责
变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可将它们封装在同一类中。
2、单一职责优点
1)降低了类的复杂度。一个类只负责一项职责比负责多项职责要简单得多。
2) 提高了代码的可读性。一个类简单了,可读性自然就提高了。
3) 提高了系统的可维护性。代码的可读性高了,并且修改一项职责对其他职责影响降低了,可维护性自然就提高了。
4) 变更引起的风险变低了。单一职责最大的优点就是修改一个功能,对其他功能的影响显著降低。
3、案例说明
在网上找了个比较好理解,也比较符合实际开发中用来思考的小案例。
有一个用户类,我们先看它的接口:
这个接口是可以优化的,用户的属性(Property)和用户的行为(Behavior)没有分开,这是一个严重的错误!非常正确,这个接口确实设计得一团糟,应该把用户的信息抽取成一个BO(Bussiness Object,业务对象),把行为抽取成一个BIZ(Business Logic,业务逻辑),按照这个思路对类图进行修正,如图1-2所示。
图1-2 职责划分后的类图
重新拆封成两个接口,IUserBO负责用户的属性,简单地说,IUserBO的职责就是收集和反馈用户的属性信息;IUserBiz负责用户的行为,完成用户信息的维护和变更。
然后IUserInfo来实现这两个接口,重写方法。
代码清单1-1 分清职责后的代码示例
.......IUserBiz userInfo = new UserInfo();//我要赋值了,我就认为它是一个纯粹的BOIUserBO userBO = (IUserBO)userInfo;userBO.setPassword("abc");//我要执行动作了,我就认为是一个业务逻辑类IUserBiz userBiz = (IUserBiz)userInfo;userBiz.deleteUser();.......
思考:上面这样是单一职责原则吗?当然不是了,你实现了两个接口,不还是把行为和属性写在一个类了,和最上面又有什么区别呢,这里只能说实现了接口隔离原则(下面会说)
那如何来确保单一原则,在实际的使用中,我们更倾向于使用两个不同的类:一个是IUserBO, 一个是IUserBiz很简单如图所示:
4、自己理解
单一职责原则有两个难点:
1) 职责划分:
一个职责一个接口,但问题是“职责”是一个没有量化的标准,一个类到底要负责那些职责?这些职责该怎么细化?细化后是否都要有一个接口或类?这些都需要从实际的项目去考虑。
比如上面写成一个类他的单一职责就是修改用户信息,为什么一定要分修改行为和修改属性。那是不是又可以在细分修改密码和修改属性呢?
2)类的冗余
如果可以追求单一职责也是没有必要的,本来一个类可以搞定的实现,如果非得修改用户名一个类,修改密码一个类来实现单一原则,这样也会让你的类变得非常多,反而不容易维护。
我自己的感悟:
1)首先要培养单一职责的思想,特别是如果代码可以复用的情况下经常思考能不能用单一职责原则来划分类。
2) 类的单一职责实现在好多时候并不切实际,但是方法上一定要保持单一职责原则。比如你修改密码的方法就是用来修改密码。这样做有个很大的好处就是便于代码调试,容易将代码的Bug找出来,一个方法只完成
一件事情,相对调试能简单很多,让其他人员能更快更好的读懂代码、理解这个类或者方法的功能。
二、里氏代换原则
这个和单一职责原则比起来,显然就好理解多了,而且也不那么模糊不清。
1、定义
官方定义:所有引用基类(父类)的地方必须能透明地使用其子类的对象。
简单理解就是:子类一般不该重写父类的方法,因为父类的方法一般都是对外公布的接口,是具有不可变性的,你不该将一些不该变化的东西给修改掉。
是不是感觉这个原则不太招人喜欢,因为我们在写代码的时候经常会去重写父类的方法来满足我们的需求。而且在模板方法模式,缺省适配器,装饰器模式等一些设计模式都会采用重写父类的方法。
怎么说呢,里氏代换原则的主要目的主要是防止继承所带来的弊端。
继承的弊端:
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。
继承会增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。
2、案例说明
SomeoneClass类,其中有一个方法,调用了某一个父类的方法。
//某一个类
public class SomeoneClass {//有某一个方法,使用了一个父类类型public void someoneMethod(Parent parent){parent.method();}
}
父类代码
public class Parent {public void method(){System.out.println("parent method");}
}
SubClass子类把父类的方法给覆盖。
public class SubClass extends Parent{//结果某一个子类重写了父类的方法,说不支持该操作了public void method() {throw new UnsupportedOperationException();}}
测试类
/**这个异常是运行时才会产生的,也就是说,我的SomeoneClass并不知道会出现这种情况,结果就是我调用下面这段代码的时候,*本来我们的思维是Parent都可以传给someoneMethod完成我的功能,我的SubClass继承了Parent,当然也可以了,但是最终这个调用会抛出异常。*/
public class Client {public static void main(String[] args) {SomeoneClass someoneClass = new SomeoneClass();someoneClass.someoneMethod(new Parent());someoneClass.someoneMethod(new SubClass());}
}
这就相当于埋下了一个个陷阱,因为本来我们的原则是,父类可以完成的地方,我用子类替代是绝对没有问题的,但是这下反了,我每次使用一个子类替换一个父类的时候,我还要担心这个
子类有没有给我埋下一个上面这种炸弹。
3、自己理解
感觉自己在开发中不太会出现上面这么愚蠢的错误。理由:
1)自己水平有限,平时在开发中使用继承的时候都是基础API的类然后重写,很少继承自己写的类,一般都是实现接口比较多。
2)第二就算我用了继承,我在传参的时候我只要稍微注意下就应该知道这个方法的参数是Parent,而如果我要放入SubClass时,就应该考虑自己有没有重写这个方法,如果重写这样肯定不行。所以也不多发生上面的错误了。
所以总的来说,要知道继承的这个隐患,在开发中注意就是。
三、接口隔离原则
1、定义
当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。
为什么要这么做呢?
其实很好理解,因为你实现一个接口就是实现它所有的方法,但其实你并不需要它的所有方法,那就会产生:一个类实现了一个接口,里面很多方法都是空着的,只有个别几个方法实现了。
这样做不仅会强制实现的人不得不实现本来不该实现的方法,最严重的是会给使用者造成假象,即这个实现类拥有接口中所有的行为,结果调用方法时却没收获到想要的结果。
2、案例说明
比如我们设计一个手机的接口时,就要手机哪些行为是必须的,要让这个接口尽量的小,或者通俗点讲,就是里面的行为应该都是这样一种行为,就是说只要是手机,你就必须可以做到的。
下面是手机接口。
public interface Mobile {public void call();//手机可以打电话public void sendMessage();//手机可以发短信public void playBird();//手机可以玩愤怒的小鸟?}
上面第三个行为明显就不是一个手机必须有的,那么上面这个手机的接口就不是最小接口,假设我现在的非智能手机去实现这个接口,那么playBird方法就只能空着了,因为它不能玩。
3、自己理解
这个没啥说的,很好理解,最上面我写单一职责原则的时候的那个案例,中间那部分就是接口隔离原则。这个思想自己要慢慢培养,然后更多的运用到实际开发中去。
四、依赖倒置原则
1、定义
依赖倒置原则包含三个含义
1) 高层模块不应该依赖低层模块,两者都应该依赖其抽象
2) 抽象不应该依赖细节
3)细节应该依赖抽象
2、案例说明
大家都喜欢阅读,阅读文学经典滋润自己的内心心灵,下面是小明同学阅读文学经典的一个类图
文学经典类
//文学经典类
public class LiteraryClassic{//阅读文学经典public void read(){System.out.println("文学经典阅读,滋润自己的内心心灵");}
}
小明类
//小明类
public class XiaoMing{//阅读文学经典public void read(LiteraryClassic literaryClassic){literaryClassic.read();}
}
场景类
public class Client{public static void main(Strings[] args){XiaoMing xiaoming = new XiaoMing();LiteraryClassic literaryClassic = new LiteraryClassic();//小明阅读文学经典xiaoming.read(literaryClassic);}}
看,我们的实现,小明同学可以阅读文学经典了。
小明同学看了一段文学经典后,忽然他想看看看小说来放松一下自己,我们实现一个小说类:
小说类
//小说类
public class Novel{//阅读小说public void read(){System.out.println("阅读小说,放松自己");}
}
现在我们再来看代码,发现XiaoMing类的read方法只与文学经典LiteraryClassic类是强依赖,紧耦合关系,小明同学竟然阅读不了小说类。这与现实明显的是不符合的,代码设计的是有问题的。那么问题在那里呢?
我们看小明类,此类是一个高层模块,并且是一个细节实现类,此类依赖的是一个文学经典LiteraryClassic类,而文学经典LiteraryClassic类也是一个细节实现类。这是不是就与我们说的依赖倒置原则相违背呢?
依赖倒置原则是说我们的高层模块,实现类,细节类都应该是依赖与抽象,依赖与接口和抽象类。
为了解决小明同学阅读小说的问题,我们根据依赖倒置原则先抽象一个阅读者接口,下面是完整的uml类图:
IReader接口:
public interface IReader{//阅读public void read(IRead read){read.read();}}
再定义一个被阅读的接口IRead
public interface IRead{//被阅读public void read();
}
再定义文学经典类和小说类
文学经典类:
//文学经典类
public class LiteraryClassic implements IRead{//阅读文学经典public void read(){System.out.println("文学经典阅读,滋润自己的内心心灵");}
}
小说类
//小说类
public class Novel implements IRead{//阅读小说public void read(){System.out.println("阅读小说,放松自己");}
}
再实现小明类
//小明类
public class XiaoMing implements IReader{//阅读public void read(IRead read){read.read();}
}
然后,我们再让小明分别阅读文学经典和小说
public class Client{public static void main(Strings[] args){XiaoMing xiaoming = new XiaoMing();IRead literaryClassic = new LiteraryClassic();//小明阅读文学经典xiaoming.read(literaryClassic);IRead novel = new Novel();//小明阅读小说xiaoming.read(novel);}
}
至此,小明同学是可以阅读文学经典,又可以阅读小说了,目的达到了。
为什么依赖抽象的接口可以适应变化的需求?这就要从接口的本质来说,接口就是把一些公司的方法和属性声明,然后具体的业务逻辑是可以在实现接口的具体类中实现的。所以我们当依赖
对象是接口时,就可以适应所有的实现此接口的具体类变化。
3、依赖的三种方法
依赖是可以传递,A对象依赖B对象,B又依赖C,C又依赖D,……,依赖不止。只要做到抽象依赖,即使是多层的依赖传递也无所谓惧。
1)构造函数传递依赖对象
在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入:
//小明类
public class XiaoMing implements IReader{private IRead read;//构造函数注入public XiaoMing(IRead read){this.read = read;}//阅读public void read(){read.read();}
}
2)Setter方法传递依赖对象
在类中通过Setter方法声明依赖关系,依照依赖注入的说法,这是Setter依赖注入
//小明类
public class XiaoMing implements IReader{private IRead read;//Setter依赖注入public setRead(IRead read){this.read = read;}//阅读public void read(){read.read();}
}
3)接口声明依赖
在接口的方法中声明依赖对象,在为什么我们要符合依赖倒置原则的例子中,我们采用了接口声明依赖的方式,该方法也叫做接口注入。
4、依赖倒置原则的经验
依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。我们在项目中使用这个原则要遵循下面的规则:
1)每个类尽量都有接口或者抽象类,或者抽象类和接口两都具备
2)变量的表面类型尽量是接口或者抽象类
3)任何类都不应该从具体类派生
4)尽量不要覆写基类的方法
如果基类是一个抽象类,而这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会有一定的影响。
5)结合里氏替换原则使用
依赖倒置原则是6个设计原则中最难以实现的原则,它是实现开闭原则的重要方法,在项目中,大家只要记住是”面向接口编程”就基本上是抓住了依赖倒置原则的核心了。
五、迪米特原则
这个原则在开发中还是非常有用的。
1、定义
大致意思是:即一个类应该尽量不要知道其他类太多的东西,不要和陌生的类有太多接触。
迪米特原则还有一个解释:Only talk to your immediate friends(只与直接朋友通信)。
什么叫直接朋友呢?每个对象都必然会与其他对象有耦合关系,两个对象之间的耦合就成为朋友关系,这种关系类型有很多,例如:组合,聚合,依赖等。朋友类也可以这样定义:出现在成员
变量,方法的输入输出参数中的类,称为朋友类。
2、案例说明
上体育课,我们经常有这样一个场景:
体育老师上课前要体育委员确认一下全班女生到了多少位,也就是体育委员清点女生的人数。如图:
分析:这里其实体育老师和体育委员是朋友,因为他们是有业务来源,而女生人数是和体育委员有业务来源(它们是朋友),但是体育老师和女生人数是没有直接业务来源的所以体育老师类中
不应该参杂女生相关信息,这就是迪米特原则
(1)没有才有迪米特原则
体育老师类
public class Teacher{//老师对体育委员发一个命令,让其清点女生人数的方法public void command(GroupLeader groupLeader){List<Girl> listGirls = new ArrayList();//初始化女生,发现老师和女生有耦合for(int i=0;i<20;i++){listGirls.add(new Girl());}//告诉体育委员开始清点女生人数groupLeader.countGirls(listGirls);}
}
体育委员类
public class GroupLeader{//清点女生数量public void countGirls(List<Girl> listGirls){System.out.println("女生人数是:"+listGirls.size());}
}
女生类
publci class Girl{
}
测试类
public class Client{public static void main(Strings[] args){Teacher teacher = new Teacher();//老师给体育委员发清点女生人数的命令teacher.command(new GroupLeader());}
}
分析:我们再回头看Teacher类,Teacher类只有一个朋友类GroupLeader,Girl类不是朋友类,但是Teacher与Girl类通信了,这就破坏了Teacher类的健壮性,Teacher类的方法竟然与一个不是
自己的朋友类Girl类通信,这是不允许的,严重违反了迪米特原则。
(2)采用迪米特原则
我们对程序进行如下修改,将类图修改如下:
修改后的老师类:(注意这里面已经没有女生信息了)
public class Teacher{//老师对体育委员发一个命令,让其清点女生人数public void command(GroupLeader groupLeader){//告诉体育委员开始清点女生人数groupLeader.countGirls();}
}
修改后的体育委员类
public class GroupLeader{private List<Girl> listGirls;public GroupLeader(List<Girl> listGirls){this.listGirls = listGirls;}//清点女生数量public void countGirls(){System.out.println("女生人数是:"+listGirls.size());}
}
修改后的测试类
public class Client{public static void main(Strings[] args){//产生女生群体List<Girl> listGirls = new ArrayList<Girl>();//初始化女生for(int i=0;i<20;i++){listGirls.add(new Girl());}Teacher teacher = new Teacher();//老师给体育委员发清点女生人数的命令teacher.command(new GroupLeader(listGirls));}
}
对程序修改,把Teacher中对Girl群体的初始化移动到场景类中,同时在GroupLeader中增加对Girl的注入,避开了Teacher类对陌生类Girl的访问,降低了系统间的耦合,提高了系统的健壮性。
在实践中经常出现这样一个方法,放在本类中也可以,放到其它类中也可以。那怎么处理呢?你可以坚持一个原则:如果一个方法放在本类中,即不增加类间关系,也对本类不产生负面影响,那就放到本类中。
迪米特原则的核心观念就是类间解耦,弱耦合,只有弱耦合后,类的复用率才可以提高。其结果就是产生了大量的中转或跳转类,导致系统复杂,为维护带来了难度。所以,我们在实践时要反
复权衡,即要让结构清晰,又做到高内聚低耦合。
3、自己理解
迪米特原则在自己开发中一定要培养这种思想,因为它没有那么模糊,而且这个原则没啥争议。
六、开闭原则
这个原则更像是前五个原则的总纲,前五个原则就是围着它转的,只要我们尽量的遵守前五个原则,那么设计出来的系统应该就比较符合开闭原则了,相反,如果你违背了太多,那么你的系统或许也不太遵循开闭原则。
1、定义
一句话,对修改关闭,对扩展开放。
就是说我任何的改变都不需要修改原有的代码,而只需要加入一些新的实现,就可以达到我的目的,这是系统设计的理想境界,但是没有任何一个系统可以做到这一点,哪怕我一直最欣赏的
spring框架也做不到,虽说它的扩展性已经强到变态。 这个就不说了,字面上也能理解个八九分,它对我来讲太抽象。虽然它很重要。
总结:
如果你理解会运用了这六大原则,那么你写出的代码一定是非常漂亮的,二不是那么臃肿,遍地第都是垃圾代码了。
相关文章:

java设计模式(2)---六大原则
设计模式之六大原则 这篇博客非常有意义,希望自己能够理解的基础上,在实际开发中融入这些思想,运用里面的精髓。 先列出六大原则:单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特原则、开闭原则。 一、单一职…...
数学建模(层次分析法 python代码 案例)
目录 介绍: 模板: 例题:从景色、花费、饮食,男女比例四个方面去选取目的地 准则重要性矩阵: 每个准则的方案矩阵: 一致性检验: 特征值法求权值: 完整代码: 运行结果: 介绍:...

Gitlab介绍
1.什么是Gitlab GitLab是一个流行的版本控制系统平台,主要用于代码托管、测试和部署。 GitLab是基于Git的一个开源项目,它提供了一个用于仓库管理的Web服务。GitLab使用Ruby on Rails构建,并提供了诸如wiki和issue跟踪等功能。它允许用户通…...

Amuse .NET application for stable diffusion
Amuse github地址:https://github.com/tianleiwu/Amuse .NET application for stable diffusion, Leveraging OnnxStack, Amuse seamlessly integrates many StableDiffusion capabilities all within the .NET eco-system Welcome to Amuse! Amuse is a profes…...

【机器学习-05】模型的评估与选择
在前面【机器学习-01】机器学习基本概念与建模流程的文章中我们已经知道了机器学习的一些基本概念和模型构建的流程,本章我们将介绍模型训练出来后如何对模型进行评估和选择等 1、 误差与过拟合 学习器对样本的实际预测结果与真实值之间的差异,我们称之…...

【11】工程化
一、为什么需要模块化 当前端工程到达一定规模后,就会出现下面的问题: 全局变量污染 依赖混乱 上面的问题,共同导致了代码文件难以细分 模块化就是为了解决上面两个问题出现的 模块化出现后,我们就可以把臃肿的代码细分到各个小文件中,便于后期维护管理 前端模块化标准…...
Python中requests、aiohttp、httpx性能对比
在Python中,有许多用于发送HTTP请求的库,其中最受欢迎的是requests、aiohttp和httpx。这三个库的性能和功能各不相同,因此在选择使用哪个库时,需要考虑到自己的需求和应用场景。 首先,让我们来了解一下这三个库的基本…...

网络原理(5)——IP协议(网络层)
目录 一、IP协议报头介绍 1、4位版本 2、4位首部长度 3、8位服务器类型 4、16位总长度 5、16位标识位 6、3位标志位 7、13位偏移量 8、8位生存空间 9、8位协议 10、16位首部检验和 11、32位源IP地址 12、32位目的IP地址 二、IP协议如何管理地址? 1、动…...

GE IS200AEPAH1BKE IS215WEPAH2BB是两种不同的压力测量模块
GE IS200AEPAH1BKE和IS215WEPAH2BB是两种不同的压力测量模块,它们都属于GE(通用电气)公司的产品。 具体来说,以下是这两种模块的一些特点和应用: IS200AEPAH1BKE:这款模块适用于需要高性价比的压力测量应用…...
Rust 与 C++ ,孰优孰劣?
Rust 与 C 是两种高级系统级编程语言,它们都在追求性能、控制底层硬件细节的同时强调安全性。以下是两者的详细对比: 目标与理念 Rust:由 Mozilla 主导开发,目标是构建一种既快速又安全的系统级编程语言,特别是解决 C…...
MySQL、Oracle的时间类型字段自动更新:insert插入、update更新时,自动更新时间戳
1.MySQL 支持的字段类型:DATETIME、TIMESTAMP drop table if exists test_time_auto_update; create table test_time_auto_update (id bigint auto_increment primary key comment 自增id,name varchar(8) …...

Testng框架集成新业务
总体框架设计见我另一篇博客:httpclienttestng接口自动化整体框架设计 <block:表示测试用例块> block后面是 测试用例的名称 ||接口名,该接口名在URL.txt里维护接口 ||get\post:表示请求的方法 get_1\2\3\4:代表加密 get: …...
springboot 单元测试
Spring Boot 单元测试是确保代码质量的重要部分,它允许我们在不实际启动整个应用的情况下测试我们的代码。在Spring Boot中,我们通常使用Spring Test模块和JUnit测试框架来编写单元测试。以下是一个简单的Spring Boot单元测试的详细代码介绍:…...

LeetCode---126双周赛
题目列表 3079. 求出加密整数的和 3080. 执行操作标记数组中的元素 3081. 替换字符串中的问号使分数最小 3082. 求出所有子序列的能量和 一、求出加密整数的和 按照题目要求,直接模拟即可,代码如下 class Solution { public:int sumOfEncryptedInt…...
[python] ETL 工作流程 Prefect
Prefect 是一个用于构建、调度和监控数据流程的 Python 库。它提供了一种简单而强大的方式来管理 ETL(Extract, Transform, Load)工作流程。下面是一个简单的示例,演示了如何使用 Prefect 来创建和运行一个简单的任务: 首先&…...

html第一次作业
常用标签 0, 骨架(!tap) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><t…...

基于java实现的KTV点歌系统
开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclip…...
GPT+向量数据库+Function calling=垂直领域小助手
引言 将 GPT、向量数据库和 Function calling 结合起来,可以构建一个垂直领域小助手。例如,我们可以使用 GPT 来处理自然语言任务,使用向量数据库来存储和管理领域相关的数据,使用 Function calling 来实现领域相关的推理和计算规…...

DeepSeek-coder 微调训练记录
简介 微调过程不再细说, 参考link进行即可. 主要是数据集. 1.3b模型微调训练占用资源信息 top信息 评估 根据DeepSeek-coder的Evaluation试进行对微调后的模型进行评估. 其中的评估库主要是evol-teacher和human-eval. 新建一个eval_ins.sh文件, 填入以下内容 LANG"…...
【Android】【Bluetooth Stack】蓝牙音乐协议分析之音频控制与信息加载(超详细)
1. 精讲蓝牙协议栈(Bluetooth Stack):SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅,【蓝牙协议栈】和【Android Bluetooth Stack】专栏会持续更新中.....敬请期待! 目录 1. 音乐信息加载 1.1 歌曲信息 1.1.1 key_c…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...

ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
用鸿蒙HarmonyOS5实现国际象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码,使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...