当前位置:  开发笔记 > 编程语言 > 正文

使用静态方法与实例化包含方法的类的性能

如何解决《使用静态方法与实例化包含方法的类的性能》经验,为你挑选了5个好方法。

我正在用C#开发一个项目.以前的程序员不知道面向对象的编程,所以大多数代码都是在大量的文件中(我们说的是4-5000行),分布在几十个,有时几百个方法上,但只有一个类.重构这样一个项目是一项艰巨的任务,所以我现在已经半熟悉了.

只要在其中一个代码文件中使用方法,就会实例化该类,然后在对象实例上调用该方法.

我想知道这样做是否有明显的性能损失?我应该"暂时"使所有方法保持静态,最重要的是,应用程序是否会以任何方式从中受益?



1> stevemegson..:

从这里开始,每次调用实例方法时,静态调用比构造实例快4到5倍.但是,我们仍然只是在谈论每次调用几十纳秒,所以你不太可能注意到任何好处,除非你有一个非常紧密的循环调用方法数百万次,并且你可以通过构建一个外部的单个实例获得相同的好处循环并重复使用它.

由于您必须更改每个呼叫站点以使用新的静态方法,因此您可能最好将时间花在逐步重构上.



2> Alex..:

我在工作中处理过类似的问题.我之前的程序员创建了1个控制器类,其中所有BLL函数都被转储.

我们现在正在重新设计系统,并根据它们应该控制的内容创建了许多Controller类

UserController,GeographyController,ShoppingController ......

在每个控制器类中,它们都有静态方法,这些方法使用单例模式调用缓存或DAL.

这给了我们两个主要优势.它稍微快一点(大约快2-3倍,但在这里说纳秒; P).另一个是代码更清晰

ShoppingController.ListPaymentMethods()

代替

new ShoppingController().ListPaymentMethods()

我认为如果类不维护任何状态,则使用静态方法或类是有意义的.



3> Moishe Lettv..:

它取决于该对象包含的其他内容 - 如果"对象"只是一堆函数,那么它可能不是世界末日.但是如果对象包含一堆其他对象,那么实例化它将调用所有构造函数(和析构函数,当它被删除时),你可能会得到内存碎片等等.

也就是说,现在看起来并不是性能是你最大的问题.



4> Keith..:

你必须确定重写的目标.如果您想要具有良好的可测试,可扩展和可维护的OO代码,那么您可以尝试使用对象及其实例方法.毕竟这是面向对象的编程,我们在这里讨论,而不是面向类的编程.

在定义实现接口的类并执行实例方法时,伪造和/或模拟对象非常简单.这使得彻底的单元测试快速有效.

此外,如果您要遵循良好的OO原则(参见http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29上的 SOLID )和/或使用设计模式,您肯定会做很多基于实例的,基于接口的开发,而不是使用许多静态方法.

至于这个建议:

创建一个JUST对象似乎很愚蠢,所以你可以调用一个看似对对象没有副作用的方法(从你的描述我假设这个).

我在dot net商店看到了很多,对我而言,这违反了封装,这是一个关键的OO概念.我不应该通过方法是否是静态来判断方法是否有副作用.除了破坏封装外,这意味着如果/当您修改它们以产生副作用时,您将需要将方法从静态更改为实例.我建议您阅读本文的开放/封闭原则,并了解上面引用的建议方法如何与此相关.

请记住,老栗子,"过早优化是所有邪恶的根源".我认为在这种情况下,这意味着不要使用不适当的技术(即面向类的编程)跳过箍,直到你知道你有性能问题.即便如此调试问题并寻找最合适的问题.



5> 小智..:

静态方法要快得多,并且占用的内存也少得多。有一种误解,认为它只是快一点。只要不将其置于循环中,它就会更快一些。顺便说一句,有些循环看起来很小,但实际上不是,因为包含该循环的方法调用也是另一个循环。您可以区分执行渲染功能的代码。不幸的是,在许多情况下,少得多的内存是正确的。实例允许与姐妹方法轻松共享信息。静态方法会在需要时询问信息。

但是就像驾驶汽车一样,速度带来责任。静态方法通常比实例实例具有更多的参数。因为实例将负责缓存共享变量,所以您的实例方法看起来会更漂亮。

ShapeUtils.DrawCircle(stroke, pen, origin, radius);

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length);

VS

ShapeUtils utils = new ShapeUtils(stroke,pen);

util.DrawCircle(origin,radius);

util.DrawSquare(x,y,width,length);

在这种情况下,只要大多数时候所有方法都使用实例变量,实例方法就值得。实例不是关于状态的,它是关于共享的,尽管“公共状态”是共享的自然形式,但它们不是相同的。一般的经验法则是:如果该方法与其他方法紧密结合--它们彼此之间非常相爱,以至于当它们被调用时,另一个也需要被调用,并且它们可能共享同一杯水- -,应使其成为实例。将静态方法转换为实例方法并不难。您只需要获取共享参数并将其作为实例变量即可。反之则更困难。

或者,您可以创建一个代理类,以桥接静态方法。尽管理论上似乎效率较低,但实践却讲述了一个不同的故事。这是因为每当需要一次(或循环)调用DrawSquare时,便直接使用static方法。但是,每当要与DrawCircle一起反复使用它时,就将使用实例代理。一个示例是System.IO类FileInfo(实例)vs File(静态)。

静态方法是可测试的。实际上,它比实例一次更具可测试性。方法GetSum(x,y)不仅可以用于单元测试,还可以用于负载测试,集成测试和使用测试。实例方法对单元测试很有用,但对其他所有测试(比单元测试BTW更为重要)来说却是可怕的,这就是为什么我们今天得到如此多的bug的原因。使ALL方法不可测试的是参数,例如(Sender s,EventArgs e)或全局状态(如DateTime.Now)没有意义。实际上,静态方法在可测试性方面是如此出色,以至于与普通的OO程序员相比,您看到的新Linux发行版的C代码中的错误更少(我知道他有很多***)。

推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有