什么时候应该而且不应该为了速度/性能而脱离OOP?

在Android的开发者文章中,Google声明你应该通常使用getter和setter声明公共变量而不是私有变量来增强嵌入式设备的性能(我认为函数调用比写入地址更昂贵)。

我想知道 – 在多大程度上应该牺牲性能来坚持OOP范式? 在其他情况下,优化是否意味着脱离“良好”的编码实践?

将其构建为可维护,然后将其破解为更快。

如果你从黑客开始 – 你可能不需要 – 维护通常是一场噩梦。

只要性能没有受到明显影响,就应该使用适当的抽象。

过早优化令人尴尬。

当公司发表类似的陈述时,我讨厌它,但不提供统计数据来量化问题。

这就是说:权衡并不是OO范式。 如果你同时拥有get和set,并且这是类设计的固有部分,那么从OO的角度来看,将变量设置为public是完全有效的。 如果性能提升足够重要,我会在这些情况下公开变量,但不会。

从某种意义上说,我认为这取决于性能对您的应用程序的重要程度,以及您通过使用您可能不会认为“好”的编码实践真正看到的性能提升程度。 但话虽这么说,我总是鼓励开发人员不要坚持教条并继续以同样的方式编写代码,因为这是你教授的方式是“正确的”。 如果你很好地记录代码并使用一致且可解释的编码实践,那么我认为做一些可能不适合“OOP范例”的事情是完全可以的。 最后,它是关于可维护的工作代码。

一般而言,所有forms的工程都是处理权衡的问题。 您需要将一种方法的成本与另一种方法的成本进行比较。

以牺牲其他任何东西为代价来牺牲可维护性总是很棘手,因为很容易低估不可维护代码的未来成本。

“程序优化的第一条规则:不要这样做。 程序优化的第二条规则(仅供专家使用!):不要这样做。“ – Michael A. Jackson

也就是说,有一些论点认为拥有访问者的好处实际上非常小。 有多少次你曾经用一种实际做某事的方法来替换刚读取/写入字段的getter或setter? 鉴于这在实践中看起来有多么罕见,人们可能会争辩说,对一切使用访问器是“过早的悲观化”。

大多数时候,你不应该在速度问题之前进行优化, 但这次你应该这样做。

这里的主要问题不是速度,而是电池。

现在,谷歌确实告诉使用避免使用getter和setter但仅限于内部使用,API应该仍然只暴露getter和setter。 您应该完全避免创建对象,更好地清空/清除对象并尽可能重用它。 从各方面来说,避免创建太多活动,通过无线连接查看通胀是最昂贵的过程。

那就是说,你必须聪明一点 。 你不能一直遵循这些建议,你的代码很快就会变得一团糟,而且我们不会把Java写成感觉像在Fortran中编码一样。

一个很好的平衡是首先创建一个在模拟器上很好地工作的干净/标准代码。 然后,当它工作得很好时,选择ressource集中部分,大多数时候循环,你减少这个。 但是在将您的应用程序发布到Android市场之前,请先执 对于许多应用程序已经杀死Android手机,我的一天甚至开始与一个完整的电池开始。

函数调用涉及什么? (我只使用了MIPS,因此其他架构可能会有所不同)。

  • 跳转到该function
  • 将寄存器保存到堆栈
  • 执行function[正文]
  • 将结果复制到返回寄存器(如果需要)
  • 恢复寄存器
  • 回到来电者

跳转/返回可能会导致CPU需要重置管道(我怀疑这可能不是现代CPU的问题,通常是预测流量控制)。 如果正文只是一个集合或获取,则可能不需要保存/恢复寄存器。 如果你在函数内部,你通常希望分别在函数调用之前和之后将返回地址推/拉到堆栈,否则你将最终进入无限循环。

将其与保存到地址或从地址读取(通常是一条指令与十几条+)相比较。

我发现Google的编码指南有点误导,如果不是完全可疑的话。

它们针对基本的OOP范例进行广告,例如针对接口而不是实现的编程,并且还促进诸如缓存字段查找之类的实践以节省计算时间。

我发现它们有问题不是因为我认为它们没有任何影响,但我觉得它们有问题,因为它优化了80%的代码,你的应用程序占用了20%的时间,而不是相反(这些数字是显然已经弥补了,但我想每个人都同意大多数Android应用程序不会将大部分时间花在评估循环表达式上。

Android应用程序真正花费的绝大部分时间是视图通胀和布局 。 如果您构建了甚至中途复杂的用户界面,并且曾经描述过您的应用程序,您会发现这些内容确实会让您的应用程序在一天结束时变得缓慢。 与视图通胀等操作相比,花时间优化循环变量似乎非常荒谬。

有趣的是,谷歌通过在附录中显示一些数字,将自己的指导方针放在荒谬的地方:

从XML扩展1视图:22,000

调用空接口方法:15

现在运行一个分析器,看看您的应用在onLayout(),Adapter.getView()或inflate()上花费了多少时间。 你可能会感到惊讶。

对于他们所讨论的特定环境和应用程序,这是一个很好的建议。 不过,我认为将其推广到其他情况并不合理。 Android应用程序基本上是小型项目,几乎没有相互依赖的方式。 因此,使用公共变量作为某些状态的接口并没有什么大不了的。

特别是,如果你在琐碎的传递getter / setter方法和公共变量之间做出选择,那么你已经大部分时间都在“破解封装”的道路上了,所以你也可能不会支付额外的性能。获得灵活性。 鉴于它是Java,无论如何,“建立世界”或多或少都是通常情况发生变化的事情。

对于一个更大的系统,使用像C ++这样的语言,你可能会对像这样的薄层抽象更有利。

只有当测试显示系统不符合其规格时,才应在牺牲性能的祭坛上牺牲设计。

我倾向于坚持“好”的编码实践,对我来说,这意味着可读性,只要我能。 只有在性能至关重要的极少数情况下,我才会偏离这一原则。 通常情况下,只有当某些事情被certificate在性能方面有所下降时。

至于吸气者和制定者; 使用getter和setter的优点是可以记录对参数的更改,并进行一些输入validation。 如果这对您无关紧要,并且性能确实非常重要,那么您可以打破抽象。 但我真的不相信通过使用例如最终类来无法优化getter和setter。

在Android的情况下,考虑性能很重要。 如果您执行类似保留大型静态引用的操作,则当用户启动另一个活动或打开键盘(重新加载视图)时,Android框架可能会强制退出您的应用程序。 达到这个限制并不需要太多。 这实际上是了解您正在开发的环境的问题。

在非移动Java开发的情况下,首先编写易于维护的代码,然后根据需要进行优化是有意义的。

谷歌没有说避免使用getter / setter并将你的变量公之于众。 他们建议不要在类中使用getter / setter来访问自己的字段。 来自http://developer.android.com/guide/practices/design/performance.html :

避免内部吸气剂/安装者

在像C ++这样的本地语言中,通常的做法是使用getter(例如i = getCount())而不是直接访问字段(i = mCount)。 这是C ++的一个很好的习惯,因为编译器通常可以内联访问,如果您需要限制或调试字段访问,您可以随时添加代码。

在Android上,这是一个坏主意。 虚拟方法调用比实例字段查找昂贵得多。 遵循常见的面向对象编程实践并在公共接口中使用getter和setter是合理的,但在类中,您应该始终直接访问字段。

数百万工时被浪费在那些愚蠢的小瘾君子和二传手上。 在大多数情况下,他们不需要。 从公共字段开始,如有必要,您可以随时更改其用法以获取/设置方法。