关于开放/封闭原则的困惑

Sak*_*man 3 oop design-patterns open-closed-principle solid-principles

开放/封闭原则规定类对于修改是封闭的,但对于扩展是开放的。假设我们想要设计一个支付系统,其中支付可以由多个处理器处理,如下所示:

    class Payment {
        void pay(paymentMethod) {
            switch (paymentMethod) {
               case 'PayPal':
               break;
               case 'Swift':
               break;
               default:
               break;
            }
        }
    }

    class PayPal {
        void pay() {
               //implement payment1
        }
    }

    class Swift {
        void pay() {
               //implement payment2
        }
    }

Run Code Online (Sandbox Code Playgroud)

假设我们是第一次实施这两种支付系统。现在如果由于某种原因任何支付系统的实现过程发生了变化,我们是不是应该修改相关的类?例如,如果我们实现PayPal,2-3年后PayPal的工作流程发生了变化,修改PayPal类是否会破坏开放/封闭原则?如果解决的话有什么解决办法?

Lin*_*ste 5

switch在类中使用该语句Payment会破坏开放/封闭原则,因为它使抽象概念与Payment具体实现紧密PayPal耦合Swift。为了添加或删除支持的付款类型,您必须编辑方法Payment.pay()

更好的设计使用interface来描述支付提供商应该是什么样子。在这种情况下,它必须有一个void pay()方法。

不应将paymentMethod参数作为 a stringPayment.pay()而应接受实现支付提供商接口的类的实例。它可以调用paymentMethod.pay()执行正确的函数。(根据您的实际设置,将此参数传递给构造函数可能比传递给方法更好)。

通过这种方式,添加或删除支付提供商变得非常容易,因为该类Payment不需要任何关于存在哪些提供商类的知识。

interface PaymentProvider {
    void pay();
}

class Payment {
    void pay(paymentMethod: PaymentProvider) {
         paymentMethod.pay();
}

class PayPal implements PaymentProvider {
    void pay() {
        //implement payment1
    }
}

class Swift implements PaymentProvider {
    void pay() {
        //implement payment2
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是另一种思考方式。我们设计的系统可以传入任何 PaymentProvider,对吧?假设 PayPal 从根本上改变了他们的实施方式。我们可以编写一个新的 PayPalV2 类来实现 PaymentProvider,并将其用作我们之前使用 PayPal 类的直接替代品。您的代码中可能只有一个地方实例化了新的 PayPay,因此您只需实例化一个新的 PayPayV2 即可。其他一切都是围绕期待 PaymentProvider 构建的,因此更改应该不重要。 (4认同)
  • 是的,我完全同意你的解决方案。但即使在你的解决方案中,假设贝宝支付实现发生了变化。那么这样的话我是不是得修改Paypal类的支付方式呢?这是否违反了开放/封闭原则? (2认同)
  • 如果 PayPal 改变了他们的实现,那么一定量的代码重写是不可避免的,这没关系。编写灵活代码背后的想法是,我们希望隔离这些更改,以便我们只需要更改一个地方的内容,而不必重新设计整个系统。基本上,可以编辑 PayPal 类来响应 PayPal 特定的更改,但您不必编辑 Payment 类。 (2认同)