SOLID & OOP 设计业务案例
Source: Dev.to
请提供您希望翻译的正文内容,我将按照要求保留源链接、格式和技术术语,仅翻译文本部分。
面向对象设计原则
封装
封装指将数据与操作这些数据的方法绑定在一起,并限制对对象某些组件的直接访问。
示例:
- 员工的工资可以是负数吗?
- 个人的年龄可以是负数吗?
这些验证属于业务逻辑和业务规则的一部分。
继承
继承将相关对象归为一类,并允许复用共享的逻辑。
示例: CreditCardPayment 继承了通用的支付行为。
红旗警示: 如果你发现自己需要重写父类的大多数方法,那么继承层次结构可能有问题。
多态
多态使得相同的方法在不同实现该方法的对象上表现出不同的行为。
示例: processPayment(amount) —— Stripe 以一种方式处理,PayPal 以另一种方式处理,但方法名保持不变。
抽象
抽象与多态相辅相成,只暴露对象的必要特性。
对面向对象的最终思考: 正确使用这些原则可以减少错误,提高可维护性,使系统更易扩展,并且能够保护业务规则的安全。
SOLID 原则
单一职责原则 (SRP)
单元应该只有一个导致其变化的原因。
不良设计:
class UserService {
validateUserData() { /* ... */ }
saveUserToDatabase() { /* ... */ }
sendWelcomeEmail() { /* ... */ }
}
良好设计:
class UserValidator { /* validates data */ }
class UserRepository { /* handles database */ }
class EmailService { /* sends emails */ }
开闭原则 (OCP)
软件实体应该对扩展开放,对修改关闭。
而不是 硬编码的条件语句:
if (paymentType == "stripe") { /* ... */ }
使用抽象:
interface PaymentGateway { pay(amount: number): void; }
class StripeGateway implements PaymentGateway { /* ... */ }
class PaypalGateway implements PaymentGateway { /* ... */ }
现在添加新提供者只需要一个新类,而不需要修改已有代码。
里氏替换原则 (LSP)
超类的对象应该可以被其子类的对象替换,而不会影响程序的正确性。
有问题的设计:
class Bird { fly() { /* ... */ } }
class Penguin extends Bird { /* cannot fly */ }
更好的设计:
class Bird { /* common behavior */ }
class FlyingBird extends Bird { fly() { /* ... */ } }
class Penguin extends Bird { /* no fly method */ }
接口分离原则 (ISP)
客户端不应被迫依赖它们不使用的接口。
不佳:
interface Worker {
work(): void;
eat(): void;
}
class RobotWorker implements Worker {
work() { /* ... */ }
eat() { /* empty */ }
}
良好:
interface Workable { work(): void; }
interface Eatable { eat(): void; }
class RobotWorker implements Workable { /* ... */ }
class HumanWorker implements Workable, Eatable { /* ... */ }
依赖倒置原则 (DIP)
高层模块应该依赖抽象,而不是具体实现。
不佳:
class OrderService {
private gateway = new StripePaymentGateway();
}
良好:
class OrderService {
private gateway: PaymentGateway; // injected
}
最终思考: OOP 提供语言,SOLID 提供语法。
业务用例:使用 SOLID 的静态工厂方法
我们需要一个灵活的支付编排系统,能够在不出现 if/else 代码杂乱的情况下添加新提供商。
1. 定义契约
interface PaymentGateway {
pay(amount: number): void;
}
2. 实现具体网关
class StripeGateway implements PaymentGateway {
pay(amount: number): void {
console.log(`💳 Paid ${amount}$ using Stripe`);
}
}
class PaypalGateway implements PaymentGateway {
pay(amount: number): void {
console.log(`💰 Paid ${amount}$ using PayPal`);
}
}
class CashOnDeliveryGateway implements PaymentGateway {
pay(amount: number): void {
console.log(`📦 Cash on Delivery: ${amount}$ will be collected`);
}
}
3. 创建静态工厂
class PaymentFactory {
static create(provider: string): PaymentGateway {
switch (provider) {
case "stripe":
return new StripeGateway();
case "paypal":
return new PaypalGateway();
case "cod":
return new CashOnDeliveryGateway();
default:
throw new Error("Payment provider not supported");
}
}
}
4. 使用工厂
const gateway = PaymentFactory.create("stripe");
gateway.pay(100);
设计如何满足 SOLID 与 OOP
- 封装(Encapsulation): 每个网关隐藏其内部实现。
- 多态(Polymorphism): 所有网关共享
pay()方法,但行为各异。 - 抽象(Abstraction): 客户端代码仅依赖
PaymentGateway接口。 - 单一职责(SRP): 每个类只有单一职责(验证、数据访问、发送邮件、处理支付等)。
扩展系统
如果需要添加新提供商(例如 Apple Pay):
class ApplePayGateway implements PaymentGateway {
pay(amount: number): void {
console.log(`🍏 Paid ${amount}$ using Apple Pay`);
}
}
在工厂中加入:
case "applepay":
return new ApplePayGateway();
无需修改已有类。
最终思考: 该示例展示了静态工厂方法结合 SOLID 原则和面向对象编程,如何构建一个简洁、可扩展的架构,适用于真实世界的支付编排平台。