最近看到同事把一个私有实例方法改成了静态方法,隐约记得有人曾经跟我说过尽量少用静态方法,于是就和同事讨论了下静态方法和实例方法有啥区别,到底怎么用比较合适。
于是在网上搜寻资料,但是很多都是粗略讲了下,或者是复制粘贴的。功夫不负苦心人,终于找到一篇文章说了静态方法和实例方法的文章,并且作者还给出了原文链接:ABAP Static vs Instance method – Which to use when?
下文直接搬运了 孟雨泊 的知乎文章 静态方法和实例方法的区别以及何时使用
我们都在争论何时使用静态方法或实例方法。 在大多数情况下,我们会采用最简单的方法,但这可能不是正确的方法。 让我们尝试探索并确定在确定“静态”或“实例”时最好的方法是什么。
在跳入差异和应该使用之前,请先检查一下静态方法和实例方法的基础。
静态方法是可以与类实例无关地调用的方法。 您只能在Static方法中访问静态属性和静态事件。
实例方法是只能使用对象引用调用的方法。 实例方法可以访问实例属性和实例事件。
从示例代码中可以看到,创建静态方法听起来不错,而且很有利可图,因为在调用方法时不涉及冗长的步骤-声明引用变量,实例化对象和调用方法。 无需执行这些步骤即可直接调用静态方法。 但是使用静态的设计不会像听起来那样好。 让我告诉你为什么:
面向对象编程的最重要方面之一是多态性–只要需要,就用更具体的实现替换默认实现。在OO ABAP中,多态性将使用方法重新定义来实现。正如我们在前面的文章“覆盖静态方法”中所讨论的,我们无法重新定义静态方法。造成这种情况的主要原因是静态方法可以独立运行。使用静态方法,可以通过显式指定定义它们的类型来调用它们。这意味着,您可以直接调用实现,而该实现不绑定到实例对象的任何特定实现。
让我们通过一个简单的场景来了解这一点–如果您有使用BAPI进行销售订单创建的静态方法。在设计时,此方法仅用于一种业务场景。现在,您想将此用于不同的业务场景。在这种新方案中,您需要在项目上设置一些其他字段,例如“更高级别”项目,确定新项目类别等。您认为简单的解决方案是在方法中添加一个代码块来执行此逻辑XYZ销售区域,ZABC订单类型。您在这里所做的事情是打开一个框,您将在其中继续添加越来越多的条件。因此违反了单一责任原则。
如果您具有Instance方法,则可以轻松继承另一个类,重新定义该方法并替换现有的实现。在这个新的实现中,您将设置其他字段并调用Super Method来完成其余的工作。
测试夹具
在ABAP单位中,可以使用称为测试夹具的特殊方法设置测试数据。使用此方法后,将在您有权访问测试数据的地方调用您的测试方法。由于每个ABAP单元测试都应该可以单独进行操作和测试,因此静态方法很难进行测试。静态方法将使用静态属性,并且由于它们正在使用静态属性,因此您必须在测试夹具方法中始终具有其他逻辑来摆脱它们。
如果您正在使用实例的对象,则可以轻松清除它。当实例化一个新对象时,旧对象将被取消引用而无需任何其他逻辑
构造函数
与实例方法的CONSTRUCTOR方法相反,使用静态方法的设计最终将使用CLASS_CONSTRUCTOR。 如前所述,CLASS_CONSTRUCTOR and CONSTRUCTOR: Who comes before whom?,很难预测何时调用CLASS_CONSTRUCTOR。 首次访问该类时可以调用CLASS_CONSTRUCTOR,即使已访问该类以获得常量值也是如此。 这使其无法操作且无法测试。
在同一会话中重用该实用程序
静态属性将绑定到内存,直到会话结束。这意味着,如果仅设置一次值,则在会话结束之前不会清除它们。如果是静态属性,则不可能在同一会话中利用相同的逻辑。例如。一个简单的实用程序类,用于生成应用程序日志。
举个例子:
- 在静态类的属性中收集日志
- 收集后调用静态方法以生成应用程序日志。
该设计似乎完全适合应为静态的实用程序类。但这是一个问题,它限制了您在同一会话中再次使用相同的逻辑而不会丢失现有信息。可以说,您正在使用此应用程序日志收集错误。现在,在同一程序中,您将不会生成另一个应用程序日志来跟踪执行的活动。由于您已收集了静态属性中的所有错误,因此除非将其复制到另一个占位符并调用Utility类以生成跟踪日志,否则当您尝试使用同一Utility类时,您将丢失错误日志数据。
另一方面,您使用实例方法和属性进行了设计,则可以简单地创建另一个实例并开始使用它来跟踪日志。
因此,基于所有这些事实,我们可以得出以下经验法则:
如果打算创建静态方法将使用的任何静态属性,请考虑创建实例方法。它将允许您使用多个实例。它还允许您控制何时可以释放绑定的内存。
如果您认为将来有机会添加条件逻辑,请使用实例方法。通过利用Redefinition,利用多态来使设计更加灵活
静态仅应用于对象创建的设计模式,例如Singleton,Factory Method,Abstract Factory,Singleton Factory,以方便对象创建。
静态应该用于纯实用程序类,而不用于助手类。
文章看完后,我简单说下我的理解:
静态方法之所以不推荐使用是因为其缺乏扩展性,一旦使用静态方法,面向对象的继承多态特性也就不再适用。后续在往静态方法中添加逻辑就会出现很多 if else,因为你无法保证不同业务方的要求是一样的。比较好的做法是创建一个接口或者抽象类,让不同业务场景自己去实现,这样即使变化也不会相互影响。
如果一定要使用静态方法,一定要确保该方法以后不会再出现修改和迭代。静态方法适用场景:工具方法比如 Math.max(),文件读写,单例,工厂模式等;
如果是并发场景,也不推荐使用静态方法,你无法保证线程安全,有可能存在多个线程同时调用,此时你无法确定得到的结果是否是对的。如果给静态方法添加锁就得不偿失了,此时,实例方法是一个好的选择。