为什么不应该将所有方法和属性都设置为全局可访问(即 public
)?
如果我将一个属性声明为 public
,你能给我举一个可能遇到的问题的例子吗?
为什么不应该将所有方法和属性都设置为全局可访问(即 public
)?
如果我将一个属性声明为 public
,你能给我举一个可能遇到的问题的例子吗?
把麦当劳看作一个对象,有一个众所周知的公开方法来点一份巨无霸汉堡。
内部会有数以千计的其他调用,用来获取制作那个巨无霸汉堡所需的材料。他们不希望您知道他们的供应链如何运作,所以您只能获得公开的 Gimme_a_BigMac()
调用,并且永远不会让您访问 Slaughter_a_cow()
或 Buy_potatoes_for_fries()
方法。
如果是为自己编写代码,而且没有人会看到,那么可以将所有内容都设置为公开。但是,如果您正在为其他人重用的库编写代码,则需要保护内部细节。这样,麦当劳可以自由切换到使用传送器将牛肉传送过来,而不必打电话给货车公司送货。最终用户永远不会知道其中的区别-他们只会获得他们的巨无霸汉堡。但是,在内部,一切都可能发生根本性的变化。
Gimme_a_BigMac()
和Slaughter_a_cow()
确实是方法。 :) 此外,如果麦当劳决定使用自己的土豆农场,内部的私有/受保护方法Buy_potatoes_for_fries()
会改为Pick_potatoes_for_fries()
,公众甚至不会注意到这个变化。对于这个很好的比喻点赞。 - Herbert将可见性作用域视为信任的内部圆圈。
以自己为例,思考哪些活动是公开的,哪些是私人或受保护的。有许多事情是您不会授权给任何人代表您处理的。有一些是允许其他人触发的,还有一些具有有限的访问权限。
同样,在编程中,作用域为您提供了创建不同信任圆圈的工具。此外,将事物设为私有/受保护可以更好地控制发生的情况。例如,您可以允许第三方插件扩展您的某些代码,而它们可以被限制在其所能到达的范围内。
因此,总体而言,作用域为您提供了额外的安全级别,并使事物保持更加组织化。
def _methodname
符号来表示私有成员。即使在编译时没有强制执行,您仍然可以在代码中使用私有成员的概念。即使支持私有成员的语言也可以通过使用反射等方式来调用私有代码。 - wprl你说存在风险?
<?php
class Foo
{
/**
* @var SomeObject
*/
public $bar;
}
$bar
应该包含一个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;
}
}
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);
}
}
如果将这两个变量都设为私有,则实现是正常的。但如果设置为公共的,只需为currentStackPosition设置错误值或直接修改List,就可以轻松破坏它。
只有暴露功能时,您才能提供可靠的契约供他人使用和信任。暴露实现只会使其成为一个可能无法正常运作的东西,除非没有人搞乱它。
其实你是可以把所有东西都公开的,并且当你明确说明了契约和正确使用对象的方式时,这并不会破坏封装性。也许不是属性,而是方法更容易隐藏。
请记住,打破封装性的不是API设计者,而是类的用户,在他们的应用程序中调用内部方法可能会这样做。您可以通过“私有”方式阻止他们这样做,或通过在非API方法前缀下划线(例如)将责任转移给他们。您真的在意某人是否通过您的库以其他方式使用它来破坏他的代码吗?我不在意。
几乎将所有内容设为私有或final-或没有API文档-另一方面-是鼓励开放源代码的可扩展性和反馈的一种方式。您的代码可以以您甚至没有想到的方式使用,如果一切都被锁定(例如C#中默认密封的方法),则可能不是这种情况。
为了避免自己犯错!
上面已经有一些很好的答案了,但我想再补充一点。这被称为最小权限原则。拥有更少的权限,更少的实体有权力破坏事物。破坏事物是不好的。
如果你遵循最小权限原则,最小知识原则(或Demeter法则)和单一职责原则也就不远了。由于你编写的用于下载最新足球比分的类遵循了这个原则,而且你必须轮询它的数据而不是直接将其转储到你的界面,所以你可以将整个类复制粘贴到下一个项目中,节省开发时间。节省开发时间是好的。
如果你很幸运,六个月后你会回到这段代码来修复一个小错误,此时你已经从中赚了gigaquads的钱。未来的自己会因为没有遵循上述原则而诅咒现在的自己,并且他将成为最少惊讶原则的受害者。也就是说,你的错误是足球比分模型的解析错误,但由于你没有遵循LOD和SRP,你会惊讶于你正在进行XML解析与输出生成的内联操作。生活中有比你自己的代码更令人惊讶的事情。相信我,我知道。
由于你遵循了所有原则并记录了你的代码,你每个星期四下午只需要工作两个小时进行维护编程,其余时间可以冲浪。