为什么方法和属性的可见度很重要?

为什么不能让所有的方法和属性都可以从任何地方访问?

如果我宣称属性是public能给我一个我可以遇到的问题的例子吗?

把能见度范围看作是信任的内部圈子。

以自己为例,思考哪些活动是公开的,什么是私人的或受保护的。 有些事情是你没有委托给任何人代表你做的。 有一些是很好的触发,有一些有限的访问。

同样,在编程中,范围为您提​​供了创build不同信任圈的工具。 另外,让事情变得私密/保护,让你更好地控制发生的事情。 例如,您可以允许第三方插件扩展您的一些代码,但可以将其限制在可以使用的范围内。

所以,概括来说,范围给你提供了额外的安全级别,使得事情更加有条理,否则就会变得更加有组织。

把麦当劳当作一个对象。 有一个众所周知的公共方法来订购一个BigMac。

在内部,将会有几十亿个其他的调用来实际获得制作Bigmac的材料。 他们不希望你知道他们的供应链是如何工作的,所以你得到的是公共的Gimme_a_BigMac()调用,永远不会允许你访问Slaughter_a_cow()或者Buy_potatoes_for_fries()方法。

为了你自己的代码,没有人会看到,继续前进,把所有东西都公之于众。 但是,如果你正在为其他人重新使用一个图书馆,那么你就去保护内部细节。 这使得麦当劳可以自由地转向使Scotty束过肉饼,而不必调用一家货运公司来陆路运送肉类。 最终用户从来不知道其中的差别 – 他们只是得到他们的BigMac。 但内部一切都可能从根本上改变。

为什么不能让所有的方法和属性都可以从任何地方访问?

因为那太贵了

我所做的每个公共方法都必须经过精心devise ,然后由build筑师团队批准 ,但必须在面对任意敌对或错误的呼叫者时加以实施 ,必须经过充分testing ,testing期间发现的所有问题必须添加回归套件 ,方法必须logging ,文件必须翻译成至less十二种不同的语言。

但最大的代价是: 这个方法必须永远保持不变,永远不变 。 如果我在下一个版本中决定我不喜欢这种方法,我不能改变它,因为客户现在依靠它。 打破公共方法的向后兼容性会给用户带来成本 ,我不喜欢这样做。 生活在糟糕的devise或公共方法的实施中会给下一版本的devise者,testing者和实施者带来很高的成本。

公开的方法很容易花费数千甚至数万美元。 在一个class级上百名学生,这是一百万美元的课程。

私人方法没有这些成本。 明智地支付股东的钱; 尽一切可能的私人。

因为这违反了封装的概念,这是OOP的一个关键原则。

你说,你跑的风险?

 <?php class Foo { /** * @var SomeObject */ public $bar; } 

你的代码指出$bar应该包含一个对象instanceof SomeObject 。 但是,任何使用你的代码的人都可以

 $myFoo->bar = new SomeOtherObject(); 

…任何依靠Foo :: $ bar作为SomeObject都会中断。 有了getter和setter以及受保护的属性,你可以执行这个期望:

 <?php class Foo { /** * @var SomeObject */ protected $bar; public function setBar(SomeObject $bar) { $this->bar = $bar; } } 

现在你可以肯定的是,任何时候Foo :: $ bar都被设置了,它将会是SomeObject对象的一个​​实例。

通过隐藏实现细节,也可以防止对象进入不一致的状态。

这是一个人为的例子(伪代码)。

 public class Stack { public List stack = new List(); public int currentStackPosition = 0; public String pop() { if (currentStackPosition-1 >= 0) { currentStackPosition--; return stack.remove(currentStackPosition + 1); } else { return null; } } public void push(String value) { currentStackPosition++; stack.add(value); } } 

如果你让这两个variables是私有的,那么实现就可以正常工作 但是,如果公开,只需要为currentStackPosition设置一个不正确的值或者直接修改列表就可以轻松破解它。

如果您只公开这些function,那么您就提供了一个可靠的合同,以便他人可以使用和信任。 揭露这个实现只是让它成为一件没有任何问题的东西。

任何语言都不需要封装,但是非常有用。 封装被用来最小化潜在的依赖关系的数量和最高的变化传播概率,同时也有助于防止不一致:

简单的例子:假设我们做了一个包含四个variables的矩形类 – 长度,宽度,面积,周长。 请注意,面积和周长是从长度和宽度(通常我不会为它们制作variables)导出的,所以长度的变化会改变面积和周长。

如果没有使用正确的信息隐藏(封装),那么使用该Rectangle类的另一个程序可以改变长度而不改变该区域,并且将会有不一致的Rectangle。 如果没有封装,就可以创build一个长度为1,宽度为3的矩形,面积为32345。

使用封装,我们可以创build一个函数,如果一个程序想要改变矩形的长度,那么该对象将适当地更新其面积和周长而不会不一致。

封装消除了不一致的可能性,并将保持一致的责任转移到对象本身上,而不是使用它的程序。

然而与此同时,封装有时是一个坏主意 ,而运动规划和碰撞(在游戏编程中)则是特别可能出现这种情况的领域。

问题是封装在需要的地方是非常好的,但是当它被用在不需要的地方,比如当有全局属性需要由一组封装来维护时,它是非常糟糕的,因为OOP强制封装不pipe怎样,你被困住了。 例如,非本地对象有许多属性,例如,任何types的全局一致性。 在OOP中会发生的事情是,每个对象都必须对全局一致性条件进行编码,并尽全力帮助维护正确的全局属性。 如果你真的需要封装,这可以很有趣,允许其他的实现。 但是如果你不需要它,你最终会在很多地方写很多非常复杂的代码,这些代码基本上都是一样的。 一切似乎都被封装起来,但实际上是完全相互依赖的。

那么事实上,你可以公开所有的东西,当你清楚地陈述什么是契约,使用对象的正确方法时,它不会破坏封装。 也许不属性,但方法往往比他们必须更隐藏。

请记住,这不是你,APIdevise者,通过公开事物来打破封装。 通过在应用程序中调用内部方法,可以这样做的是类的用户。 你可以为了试图这样做(即声明私有方法),或者把责任传递给它们(例如,通过在非API方法前添加“_”)。 你真的在乎是否有人用你build议的另一种方式使用你的图书馆来破坏他的代码吗? 我不。

另一方面,几乎所有的事情都是私有的或者最终的 – 或者在没有API文档的情况下离开它们 – 是一种阻止在开源中扩展和反馈的方式。 你的代码可以以你甚至没有想到的方式使用,当所有东西都被locking的时候(例如在C#中使用默认方法进行密封),情况可能不是这样。

你唯一可能遇到的问题是,如果你不使用私有受保护抽象静态最终接口或其他什么,人们会看到你“不酷”。 这件东西就像名牌服装或苹果产品 – 人们不是因为需要购买,而是为了跟上他人。

是的,封装是一个重要的理论概念,但在实践中“私人”和朋友很less有意义。 他们可能在Java或C#中有一定的意义,但是在像PHP这样的脚本语言中,使用“private”或“protected”是很愚蠢的,因为封装是由编译器发明的,PHP中不存在。 更多细节 。

另请参阅这个优秀的回应和@troelskn和@mario评论在这里

可见性只是为了您自己的利益而使用的 ,以帮助您不破坏自己的代码。 如果你使用正确的话,你会帮助别人(谁在使用你的代码)不破坏自己的代码(通过不使用你的代码)。

在我看来,最简单的,广为人知的例子是Singleton模式。 这是一个模式,因为这是一个普遍的问题。 (来自维基百科的pattern的定义:

是loggingdevise问题解决scheme的正式方式

在Wikipedia中的单例模式的定义:

在软件工程中,单例模式是一种用于实现单例math概念的devise模式,通过将类的实例化限制为一个对象。 当需要恰好一个对象来协调系统中的操作时,这非常有用。

http://en.wikipedia.org/wiki/Singleton_pattern

该模式的实现使用私有构造函数。 如果你不把构造函数私人化,任何人都可能会错误地创build一个新的实例,并打破只有一个实例的全部观点。

你可能会认为以前的答案是“理论上的”,如果你在Doctrine2实体中使用public财产,你打破懒惰加载。

为了拯救你自己!

上面有一些很好的答案,但我想补充一点。 这被称为最小特权原则 。 用较less的特权,较less的实体有权破坏事物。 打破事情是不好的。

如果遵循最小特权的原则,那么最小知识 (或德米特法)和单一责任原则的原则就不远了。 由于你写下载最新足球比分的课程遵循这个原则,你必须轮询它的数据,而不是直接扔到你的界面,你复制和粘贴到下一个项目,节省开发时间。 节省开发时间是好的。

如果你幸运的话,你将在6个月后回到这个代码来修复一个小错误,在你赚了1000亿美元之后。 未来的自我会因为没有遵循上述原则而徒劳无功,他将成为违反最不惊奇原则的受害者。 也就是说,你的bug是足球比分模型中的一个分析错误,但是因为你没有遵循LOD和SRP,所以你对于你的输出生成XML内容的事实感到惊讶。 人生中有很多令人惊讶的事情,而不是你自己的代码的可怕之处。 相信我,我知道。

由于您遵循了所有原则并logging了您的代码,因此您每周四下午在维护编程中工作两个小时,其余时间则在冲浪。

Interesting Posts