六大设计原则
# 六大设计原则
以下六大原则,是我们要追求的标准,但实际开发中因为一些情况(为了更高效)或者其他原因,我们可能会违反它们,但我们应该尽量避免这种情况的出现,因为按照这些原则设计出来的软件,它的可维护性、健壮性更好。
# 单一责任原则
单一职责原则的定义是:应该有且仅有一个原因引起类的变更。
换句话说,一个类应该只负责一项功能或职责,并且这个职责应该是明确的、独立的。如果一个类承担了多个职责,那么当其中一个职责发生变化时,可能会对其他职责造成影响,从而增加代码的复杂性和维护难度。
假设你有一个Employee
类,它负责员工的基本信息管理,如姓名、职位等,同时也负责计算员工的工资。按照单一职责原则,这样的设计并不理想,因为员工信息的变化(如更新个人信息)和工资计算的变化(如调整税率)是两种不同的需求,它们可能会独立地发生改变。
因此我们建议在设计接口时,设计成2个接口。
这样一来,就会有如下几点优势:
- 类的复杂性降低,实现什么职责都有清晰明确的定义;
- 可读性提高,复杂性降低;
- 可维护性提高,可读性提高;
- 变更引起的风险降低
当一个类承担过多的责任时,它会变得庞大而复杂,使得理解和维护变得更加困难。随着功能的不断增加,代码会越来越难以阅读和修改。此外,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。
但请记住,单一职责原则最难划分的就是职责。一个职责一个接口,但问题是“职责”没有一个量化的标准,一个类到底要负责那些职责?这些职责该怎么细化?细化后是否都要有一个接口或类?这些都需要从实际的项目去考虑,因此单纯的追求单一原则是不可取的,要根据实际情况而定。
对于接口,我们在设计的时候一定要做到单一,但是对于实现类就需要多方面考虑了。生搬硬套单一职责原则会引起类的剧增,给维护带来非常多的麻烦,而且过分细分类的职责也会人为地增加系统的复杂性。本来一个类可以实现的行为硬要拆成两个类,然后再使用聚合或组合的方式耦合在一起,人为制造了系统的复杂性。
# 里氏替换原则
里氏替换原则的核心思想是:
子类必须能够替换其基类,并且在不修改调用者的前提下,保证程序的正确性。
简单来说,如果你有一个基类(父类)和一个继承自该基类的子类,那么在任何可以使用基类的地方,也应该能够使用子类而不会出现问题。这要求子类的行为不应该破坏基类的契约,即子类应当保持与基类相同的接口行为,而且不应改变基类的预期行为。
# 依赖倒置原则
依赖倒置原则的核心思想是:
高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
简单来说,依赖倒置原则提倡依赖于接口或抽象类,而不是具体的实现类。这样做的目的是为了使代码更加灵活,易于扩展和维护。
高层模块通常是指那些专注于业务逻辑实现的模块。它们负责定义应用程序的核心功能和处理复杂的业务流程。
底层模块是指那些提供具体实现细节的模块。它们通常负责执行具体的任务或提供特定的服务。
依赖倒置原则的两个方面
- 高层模块与低层模块的关系:
- 高层模块负责业务逻辑的实现,而低层模块则提供具体的实现细节。
- 高层模块应该依赖于抽象,而不是具体的实现细节。这样即使底层实现发生变化,高层模块也不受影响。
- 抽象与细节的关系:
- 抽象是指接口或抽象类,而细节是指具体的实现类。
- 抽象不应该依赖于细节,相反,细节应该依赖于抽象。这意味着具体的实现类应该实现抽象接口或继承抽象类,而不是反过来。
在项目中,大家只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心。
# 接口隔离原则
接口隔离原则的核心思想是:
一个类不应该被迫依赖于它不需要的方法。换句话说,客户端不应该被迫依赖于它不需要的接口中的方法。
ISP强调的是精简接口,使得类、模块或组件之间的依赖更加明确和精细。这可以通过将庞大的接口分解成更小、更具体的接口来实现,从而使实现类只需要知道并实现它真正需要的那一部分。
接口隔离原则的主要目标是提高系统的灵活性、可维护性和可扩展性。通过遵循ISP,可以达到以下目的:
- 减少耦合:类之间依赖的接口越少,耦合度就越低,从而提高了系统的灵活性。
- 提高复用性:精简的接口更容易被复用,因为它们不会包含不必要的方法。
- 简化设计:通过分解大的接口为多个小接口,可以简化类的设计,使每个类更加专注和独立。
- 易于维护:当接口更小、更具体时,修改或扩展接口变得更简单,因为影响范围更小。
# 迪米特法则
迪米特法则的核心思想是:
一个对象应该对其它对象有尽可能少的知识。
具体来说,一个类应该尽可能减少与其他类的交互。类与类之间的通信应该保持在最小限度,每个类都应该有清晰的职责边界,并且应该避免不必要的直接通信。
迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。其要求的结果就是产生了大量的中转或跳转类,导致系统的复杂性提高,同时也为维护带来了难度。读者在采用迪米特法则时需要反复权衡,既做到让结构清晰,又做到高内聚低耦合。
在实际应用中,如果一个类跳转两次以上才能访问到另一个类,就需要想办法进行重构了,为什么是两次以上呢?因为一个系统的成功不仅仅是一个标准或是原则就能够决定的,有非常多的外在因素决定,跳转次数越多,系统越复杂,维护就越困难,所以只要跳转不超过两次都是可以忍受的,这需要具体问题具体分析。
# 开闭原则
迪米特法则的核心思想是:
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
软件实体应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。