六大设计原则
1、单一职责原则(SRP)
就一个类而言,应该仅有一个引起它变化的原因。也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。
单一职责原则是实现高内聚、低耦合的指导方针。
解决方案:
将不同的职责封装到不同的类或模块中。一个类只负责一项职责。
比如在职员类里,将工程师、销售人员、销售经理这些情况都放在职员类里考虑,其结果将会非常混乱,在这个假设下,职员类里的每个方法都要if else判断是哪种情况,从类结构上来说将会十分臃肿。
2、开放封闭原则(OCP)
对象或实体应该对扩展开放,对修改封闭。。即软件实体应尽量在不修改原有代码的情况下进行扩展。
解决方案:
- 使用接口和抽象类,为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成;
l 参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;
l 抽象层尽量保持稳定,一旦确定即不允许修改;
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在Java、C#等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成。想要达到这样的效果,我们需要使用接口和抽象类,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。
3、里氏替换原则(LSP)
任何基类可能出现的地方,子类一定可以出现。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
遵循里氏替换原则时,子类尽量不去重写基类的方法,如果需要大量重写时,建议再创造一个基类的基类,并继承之,使得其和之前的基类是兄弟关系,而不是父子关系。
4、依赖倒置原则(DIP)
抽象(接口/抽象类)不应该依赖于细节,细节应该依赖于抽象(接口/抽象类)。
高层模块不应该依赖于低层模块,两者都应该依赖其抽象。
抽象指的是接口或者抽象类;细节指的是具体实现类。
中心思想是面向接口编程;针对接口编程,依赖于抽象而不依赖于具体。
比如有接口ICar,子类有Car1和Car2.我们在处理逻辑的时候,直接调用ICar的方法,而不是在代码里调用Car1或者Car2.
如何在项目中使用这个规则呢?
每个类尽量都有接口或者抽象类,或者都有
变量的表面类型尽量是接口或者抽象类
5、接口隔离原则(ISP)
客户端不应该依赖它不需要的接口
类间的依赖关系应该建立在最小的接口上
不应强迫客户端实现一个它用不上的接口,或是说客户端不应该被迫依赖它们不使用的方法,使用多个专门的接口比使用单个接口要好的多!
比如,为了减少接口的定义,将许多类似的方法都放在一个接口中,最后会发现,维护和实现接口的时候花了太多精力,而接口所定义的操作相当于对客户端的一种承诺,这种承诺当然是越少越好,越精练越好,过多的承诺带来的就是你的大量精力和时间去维护!
6、迪米特法则,又称最少知道原则(Demeter Principle)
一个对象应该对其他对象有最少的了解
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
迪米特法则对类的低耦合提出的明确的要求,包含了以下含义:
l 只和朋友交流:朋友类的定义是这样的:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
l 朋友也是有距离的:迪米特法则要求类“羞涩”一点,尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private、package-private、protected等访问权限。
l 是你自己的就是你自己的:在实际应用中经常会出现这样一个方法:放在本类中也可以,放在其他类中也没有错,那怎么去衡量呢?正确做法:如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。
迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异