SOLID Principles:编写在真实世界中经得起考验的代码
Source: Dev.to
请提供您希望翻译的文章正文内容,我将为您将其译成简体中文,并保留原始的格式、Markdown 语法以及技术术语。谢谢!
引言
编写软件不仅仅是让东西能够运行。
更重要的是让它们今天、明天以及一年后依然能够运行。
上周,我们探讨了事件驱动架构——系统如何通信与扩展。
本周,我们将进入更为基础的内容:SOLID Principles(SOLID 原则)。
SOLID 不是一个框架或库;它是一种思考方式。每个字母代表一个原则,帮助我们设计出清晰、灵活且易于维护的软件。
单一职责原则 (SRP)
一件事 = 一项工作
一个类应该只有一个职责,并且只有一个导致其变化的原因。
如果一个类同时处理用户注册、发送电子邮件以及将数据保存到数据库,它的职责就太多了。正如勺子不应该刷牙一样,类也不应该尝试做所有事情。
现实世界的类比
- 厨师烹饪。
- 司机驾驶。
- 老师教学。
图示
classDiagram
class UserService {
+registerUser()
}
class EmailService {
+sendEmail()
}
class UserRepository {
+save()
}
UserService --> EmailService
UserService --> UserRepository
图 1:单一职责原则 – 每个类只有一个职责。
开闭原则 (OCP)
你可以向玩具箱中添加新玩具,而不会破坏已有的玩具。
在不修改现有代码的情况下扩展行为。
与其每次需要新功能时都修改旧代码,不如对其进行扩展。良好的软件设计能够在不破坏已有结构的前提下实现增长。
现实世界的类比
你不会为了添加新设备而拆除房屋的墙壁,只需把它插入已有的插座即可。
图示
classDiagram
class Payment {
<>
+pay(amount)
}
class CreditCardPayment {
+pay(amount)
}
class PayPalPayment {
+pay(amount)
}
class PaymentProcessor {
+process(payment)
}
Payment Payment
图 2:开闭原则 – 在不修改现有代码的情况下扩展功能。
Liskov 替换原则 (LSP)
如果你把巧克力牛奶换成草莓牛奶,它仍然应该表现得像牛奶一样。
如果某物是另一种事物的“类型”,它就应该恰当地表现为那种类型。
示例
“企鹅是一种鸟”,但“所有鸟都会飞”对企鹅来说是错误的。问题出在设计假设,而不是企鹅本身。
规则: 不要强迫子类违背预期。如果子类不能完全表现得像其父类,那么继承设计就是错误的。
图示
classDiagram
class Bird
class FlyingBird {
<>
+fly()
}
class Sparrow
class Penguin
接口分离原则 (ISP)
不要强迫某人去做他们不需要做的事。
示例
如果你给孩子分配“做饭”和“开车”等职责,那就太多了。只给他们真正需要的职责。
类比
电视遥控器只有电视按钮;空调遥控器只有空调按钮。大型接口就像巨大的遥控器,而小而专用的接口则简洁且聚焦。
图示
classDiagram
class Workable {
<>
+work()
}
class Eatable {
<>
+eat()
}
class Human
class Robot
Workable
+save()
}
class MySQLDatabase
class MongoDatabase
class OrderService {
+processOrder()
}
Database Database
图 5:依赖倒置原则 – 依赖抽象,而不是具体实现。
依赖倒置原则 (DIP)
高层模块不应依赖低层模块;两者都应依赖抽象。这降低了耦合度,使系统更具灵活性。
(上图说明了该原则。)
Final Thoughts
SOLID 原则不仅仅是理论;它们帮助你编写代码,使得:
- 更容易理解
- 更容易扩展
- 更容易维护
- 不容易出错
今天的良好设计可以让你免于明日的痛苦。当你遵循 SOLID 时,软件会干净地成长——就像一个井然有序的玩具箱。
What about you?
你是否曾在项目中因为糟糕的设计而在后期遇到问题?你最难以掌握的 SOLID 原则是哪一个?欢迎在评论区讨论。