不使用setter和getter真的那么错吗?
使用getter和setter方法是否真的那么错误?
在PHP中,如果只考虑PHP而不是C#、Java等(在这些语言中编译器会进行优化),我发现getter和setter是一种浪费资源的做法,因为你只需要代理私有字段的值,而不需要做其他任何操作。
在我的设置中,我创建了两个简单的类,一个类有五个私有字段,通过五个getter/setter对字段进行封装(这看起来几乎和Java代码一模一样),另一个类有五个公共字段,然后在创建实例后调用memory_get_usage()。使用getter/setter的脚本使用了59708字节的内存,而使用公共字段的脚本使用了49244字节的内存。
在任何重要的类库(例如网站框架)的上下文中,这些无用的getter和setter方法会导致内存占用量巨大。我在PHP中为我的雇主开发了一个框架(这是他们的选择,而不是我的。如果我有选择的话,我不会选择PHP用于此目的,但是话虽如此,PHP并没有对我们施加任何不可逾越的限制),当我将类库重构为使用公共字段而不是getter和setter时,每个请求的内存使用量至少减少了25%。
__get()、__set()和__call()这些“魔术”方法在处理接口更改时非常有用。当您需要将字段迁移到getter/setter(或getter/setter迁移到字段)时,它们可以使依赖代码对此过程透明。对于解释性语言来说,即使使用Eclipse PDT或Netbeans提供的相对较好的代码敏感性支持,查找字段或方法的所有使用也有点困难,因此这些魔术方法对于确保旧接口仍然委托给新功能非常有用。
假设我们有一个使用字段而不是getter/setter开发的对象,并且我们想将名为'field'的字段重命名为'fieldWithBetterName',因为'field'不合适,或者不再准确描述其用途,或者完全错误。并且我们想要将名为'field2'的字段更改为从数据库中延迟加载其值,因为初始值是未知的,使用一个getter...
class Test extends Object { public $field; public $field2; }
变成
class Test extends Object { public $fieldWithBetterName = "LA DI DA"; private $_field2; public function getField2() { if ($this->_field2 == null) { $this->_field2 = CrapDbLayer::getSomething($this->fieldWithBetterName); } return $this->_field2; } public function __get($name) { if ($name == 'field') { Logger::log("use of deprecated property... blah blah blah\n".DebugUtils::printBacktrace()); return $this->fieldWithBetterName; } elseif ($name == 'field2') { Logger::log("use of deprecated property... blah blah blah\n".DebugUtils::printBacktrace()); return $this->getField2(); } else return parent::__get($name); } } $t = new Test; echo $t->field; echo $t->field2;
(顺便提一下,那个“extends Object”的部分只是我几乎所有东西都使用的一个基类,它具有一个__get()和__set()的声明,当访问未声明的字段时会抛出异常)
您也可以使用__call()方法进行反向操作。这个例子相当脆弱,但很容易清理:
class Test extends Object { public $field2; public function __call($name, $args) { if (strpos($name, 'get') === 0) { $field = lcfirst($name); // 欺骗,我知道。php 5.3或更高版本。不过没有它也不难做到。 return $this->$field; } parent::__call($name, $args); } }
在PHP中,如果setter必须执行某些操作,或者getter必须延迟加载某些内容,或者确保某些内容已经创建,那么使用getter和setter方法是很好的选择;但是,如果getter和setter除了代理字段之外什么都不做,特别是使用上述几种技术来管理接口更改,它们是不必要且浪费资源的。
在编程中,使用getter和setter的目的是为了在一个地方添加逻辑来修改字段,而不是在每个想要修改或检索字段的地方都进行修改。此外,使用getter和setter还可以在类级别上控制字段的行为。
然而,有人认为不使用getter和setter也可以达到相同的效果,因为它们认为这种方法会增加代码的复杂性,并且不值得这样做。他们认为直接访问字段可以提高代码的可读性和性能。
这种争论的出现是因为不同的编程风格和个人偏好。有些人喜欢使用getter和setter来封装字段,以便在以后修改字段时可以更容易地添加逻辑。而另一些人则认为直接访问字段更简洁和高效。
对于那些支持使用getter和setter的人来说,他们认为这种方法可以提高代码的可维护性和灵活性。通过使用getter和setter,可以将字段的修改逻辑集中在一处,以便在需要修改时可以更方便地进行更改。此外,使用getter和setter还可以在类级别上对字段进行控制,以确保字段的有效性和一致性。
然而,对于那些不支持使用getter和setter的人来说,他们认为这种方法会增加代码的复杂性,并且不值得这样做。他们认为直接访问字段可以提高代码的可读性和性能。此外,他们认为使用getter和setter会产生不必要的开销,因为它们会引入额外的方法调用和内存开销。
为了解决这个问题,可以根据个人偏好和项目需求来决定是否使用getter和setter。如果项目要求需要对字段进行封装和控制,那么使用getter和setter可能是一个好的选择。然而,如果项目要求更注重性能和简洁性,那么直接访问字段可能更合适。
总之,是否使用getter和setter是一个个人偏好和项目需求的问题。使用getter和setter可以提高代码的可维护性和灵活性,但也会增加代码的复杂性和开销。因此,选择是否使用getter和setter应该根据具体情况进行权衡。
是否使用setter和getter真的那么错?
不使用属性访问器的主要问题是,如果发现以后需要将字段更改为属性-例如,在子类中将其作为计算属性使用-那么会破坏API的客户端。对于发布的库来说,这是不可接受的;对于内部库来说,这只是需要大量的工作来修复问题。
对于私有代码或小型应用程序,可能可以随意使用。IDE(或文本编辑器)可以让您生成访问器样板并使用代码折叠隐藏它。可以说,这使得使用getter和setter在机械上相当容易。
请注意,一些编程语言具有合成默认字段+getter+setter的功能-例如,Ruby通过元编程实现,C#具有自动实现的属性。而Python则完全避开了这个问题,它允许您重写属性访问,将属性封装在需要它的子类中,而无需事先烦扰它。(这是我最喜欢的方法。)
如果需要将属性转化为计算属性而不破坏向后兼容性,则可以使用__get和__set。
“synthetise”是什么意思?是指“synthesize”还是“simulate”?
是指合成。在Ruby中,调用attr_accessor :foo之后,类实际上会包含方法def foo; ; end和相应的setter-它们不是通过“伪造”的方式实现的,例如使用method_missing和哈希表。对于C#来说也是一样,编译器会生成一个真正的私有字段和简单的访问器方法。
我从来没见过这个词-我猜它是英国的词。我知道这个词的拼写是“synthesize”。没问题!只是好奇你指的是哪个词。
哦,你是指拼写。那只是我英语非母语的表现。(我使用-ise,因为这样我就不需要记住-ize不正确的例外情况。)维基百科说,避免使用-ise是美式英语,英式英语允许在任何地方都使用这两种拼写,首选是根据你遵循的风格指南而定。
加上字母t的差异。
那是一个常见的错误。