Design Principles in Java

2025 年 5 月 5 日 | 阅读 6 分钟

在 Java 中,设计原则是设计决策中用作规则的一组建议。在 Java 中,设计原则类似于设计模式的概念。设计原则和设计模式之间的唯一区别在于,设计原则更加通用和抽象。设计模式包含更实用的建议和具体的指导。设计模式与整个类问题相关,而不仅仅是泛化的编码实践。

Design Principles in Java

以下是一些最重要的设计原则:

SOLID 原则

  1. SRP
  2. LSP
  3. ISP
  4. 开闭原则
  5. DIP

其他原则

  1. DRY 原则
  2. KISS 原则
  3. 组合优于继承原则

让我们一一理解所有原则

DRY 原则

DRY 原则代表 Don't Repeat Yourself(不要重复自己)原则。它是所有编程语言的常见原则之一。DRY 原则表示:

在一个系统中,每段逻辑都应该有单一的、无歧义的表示。

让我们以 DRY 原则为例

狗和猫说话方式不同,但它们都需要吃食物。它们共同的功能是“吃食物”,所以我们可以将这个共同的功能放到父类“动物”中,然后我们在子类“狗”和“猫”中扩展这个父类。

现在,每个类都可以专注于自己独特的逻辑,因此无需在两个类中都实现相同的功能。

编译并运行上面的代码后,我们将看到以下输出:

输出

Eat food
Cat Meow!
Eat food
Dog Woof!	

违反 DRY 原则

违反 DRY 原则的情况被称为 WET 解决方案。WET 是以下缩写的组合:

  1. 写两次
  2. 我们喜欢打字
  3. 每次都写
  4. 浪费大家两次。

这些重复并非总是坏事,因为有时为了使代码的依赖性降低、更具可读性、内在类不相似等,重复是值得提倡的。

SRP

SRP 是另一个设计原则,代表 单一职责原则。SRP 原则指出,一个类不应该有两个功能。它也可以转述为:

类应该只有一个且仅有一个改变的理由。当存在多个职责时,存在多个改变该类的理由。因此,同一个类中不应存在多个可能受影响的独立功能。

SRP 原则有助于我们:

  1. 在不继承或实现我们类不需要的方法的情况下继承一个类。
  2. 处理 bug。
  3. 在不混淆共同依赖关系的情况下实现更改。

LSP

LSP 是另一个设计原则,代表 Liskov 替换原则LSP 指出,派生类应该能够在不改变我们代码的情况下替换基类。

LSP 与 SRP 和 ISP 密切相关,因此,违反 SRP 或 ISP 可能就是违反(或成为)LSP。LSP 违反的原因是,如果一个类执行多个功能,那么扩展该类的子类不太可能在功能上实现这两个或多个功能。

DIP

另一个最重要的设计原则是 DIP,即 依赖倒置原则。该原则指出,低级和高级模块应该解耦,这样低级模块的更改就不需要重新编写高级模块。

高级和低级模块不应该相互依赖。它们应该依赖于抽象,例如接口。依赖倒置原则还指出,细节应该依赖于抽象,而不是抽象应该依赖于细节。

KISS 原则

这是另一个设计原则,代表 Keep It Simple and Stupid(保持简单愚蠢)原则。该原则只是一个提醒,让我们保持代码对人类来说可读且简单。如果一个方法处理多个用例,我们需要将其拆分成更小的函数。

KISS 原则指出,在大多数情况下,堆栈调用不应严重影响程序的性能,除非效率不是极其重要。

另一方面,冗长且难以阅读的方法对于人类程序员来说将非常难以维护和查找 bug。违反 DRY 原则可能是我们自己造成的,因为如果我们有一个执行多个任务的方法,我们就无法调用该方法来执行其中一项任务。因此,我们将为该任务创建另一个方法。

ISP

ISP 是另一个设计原则,代表 接口隔离原则。该原则指出,客户端不应该被限制依赖于他们并未全部使用的接口。这意味着接口应包含确保功能所需的最小方法集,并且仅限于一个功能。

例如,如果我们创建一个 Burger 接口,我们不需要实现 addCheese() 方法,因为并非所有类型的 Burger 都提供奶酪。

让我们假设所有汉堡都需要烘烤并添加酱汁,并按以下方式定义该汉堡接口:

现在,让我们在 VegetarianBurger 和 CheeseBurger 类中实现 Burger 接口。

素食汉堡有卷心菜和番茄,而芝士汉堡有奶酪,但需要烘烤和酱汁,这些都在接口中定义。如果 addCheese() 和 addTomatoandCabbage() 方法位于 Burger 接口中,那么这两个类都必须实现它们,即使它们不需要两者。

开闭原则

开闭原则是另一个重要的设计原则,属于 SOLID 原则。该原则指出,方法、对象或类应该对修改关闭,但对扩展开放。简单来说,该原则表明我们应该在考虑未来可能更新的情况下实现我们的模块和类。通过这样做,我们的模块和类将具有通用的设计,并且为了扩展它们的行为,我们不需要更改类本身。

我们可以创建新的字段或方法,但方式是我们不需要修改旧代码、删除已创建的字段以及重写已创建的方法。

开闭原则主要用于防止回归并确保向后兼容性。

组合优于继承原则

组合优于继承原则是 Java 中另一个重要的设计原则。该原则帮助我们在 Java 中实现灵活且可维护的代码。该原则指出,我们应该实现接口而不是扩展类。我们何时实现继承:

  1. 类需要实现所有功能
  2. 子类可以作为我们父类的替代品。

同样,我们何时使用组合:

  1. 类需要实现一些特定的功能。