关于开放/封闭本金的困惑

问题描述

打开/关闭原则指出,对类而言,修改关闭的,而对扩展来说是开放的。假设我们要设计一种付款系统,其中的付款可以由多个处理器处理,如下所示:

    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
        }
    }

假设我们是第一次实施两种付款系统。现在,如果由于某种原因改变了支付系统的实施流程,我们是否不必修改相关类别?例如,如果我们实施PayPal,并且在2-3年后更改了PayPal的工作流程,那么修改PayPal类是否不会违反开放/封闭原则?如果可以,该怎么解决

解决方法

现在,如果由于某种原因而改变了支付系统的实施流程,我们是否不必修改相关类别?例如,如果我们实施PayPal,并且在2-3年后更改了PayPal的工作流程,那么修改PayPal类是否不会违反开放/封闭原则?

不,它不会破坏它。如果PayPal的工作流程发生变化,则必须将其反映在扩展PayPal payment method的类中。

我给您举个例子:假设明天您想再添加一个payment method - Transferwise,现在该模式告诉我们“软件实体(类,模块,函数等)应为扩展名,但为了修改而关闭”,这意味着如果您需要修改任何现有类以添加新的payment method,那么您将打破开放/封闭原则,而另一方面,您只需扩展{{1} }在您的新PaymentMethod类中,您无需进行任何更改即可扩展系统,并且遵守该模式

,

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

更好的设计使用interface来描述支付提供商的外观。在这种情况下,它必须具有void pay()方法。

paymentMethod应该接受实现支付提供者接口的类的实例,而不是将string参数作为Payment.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
    }
}
,

我认为这里的问题归结为开放/封闭原则的定义。具体来说,它真的是真的表示代码在编写之后就不会更改吗?

尽管许多人(包括我自己)已经使用该定义代替OCP,但这是一个过分的简化。 OCP最初由Bertrand Meyer在面向对象的软件构造中发布。我认为可以在该书的第二版(从第60页开始)中找到该问题的答案,其中指出了OCP的一些“例外”。

  • 如果您可以控制原始软件并可以对其进行重写,以使其能够轻松解决多种客户端的需求,那么您应该这样做。
  • 开放式原则和继承中的重新定义都不是解决的方法 设计缺陷,更不用说bug。 如果模块有问题,您应该 修复它-不要保留原样,并尝试纠正派生中的问题 模块...开闭原理及相关 技术旨在适应健康的模块: 尽管它们可能不足以满足某些新用途,但要满足自己的明确定义 要求,以使自己的客户满意。

很显然,Meyer并不打算永远不要重写遗留代码。如果新要求使现有逻辑的一部分无效,则重写它可能是一种明智的方法,而绝不是OCP禁止的。