SOLID & OOP 设计业务案例

发布: (2026年1月20日 GMT+8 20:54)
6 min read
原文: Dev.to

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 原则和面向对象编程,如何构建一个简洁、可扩展的架构,适用于真实世界的支付编排平台。

Back to Blog

相关文章

阅读更多 »