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

时间:2011-09-12 17:22:44

标签: php oop visibility encapsulation

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

如果我将属性声明为public,你可以 给我一个例子 我可以遇到的问题吗?

12 个答案:

答案 0 :(得分:146)

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

在内部会有几个其他的调用来实际获取用于制作Bigmac的材料。他们不希望您知道他们的供应链是如何运作的,所以您得到的只是公开Gimme_a_BigMac()电话,永远不会允许您访问Slaughter_a_cow()Buy_potatoes_for_fries()方法

对于你自己的代码,没有人会看到,继续公开。但是,如果您正在为其他人重复使用库,那么您可以保护内部细节。这让麦当劳可以自由地改用Scotty光束而不是打电话给卡车运输公司来陆续运送肉类。最终用户永远不会知道差异 - 他们只是得到了他们的BigMac。但内部一切都可能从根本上改变。

答案 1 :(得分:45)

  

为什么不能让所有方法和属性都可以从任何地方(即公共)访问?

因为这太贵了

我制作的每一种公共方法都必须由建筑师团队仔细设计然后批准,必须实施面对任意敌对或错误的呼叫者强大,必须经过全面测试,测试期间发现的所有问题都必须有回归套件补充说,该方法必须记录,文档必须翻译至少12种不同的语言。

最大的成本是:该方法必须保持,不变,永远,永远,阿门。如果我在下一个版本中决定我不喜欢该方法所做的那样,我就无法改变它,因为客户现在依赖它。打破公共方法的向后兼容性会对用户造成成本,我不愿意这样做。生活在糟糕的设计或实施公共方法的过程中,下一版本的设计师,测试人员和实施者都会付出高昂的代价。

公共方法很容易花费数千甚至数万美元。在课堂上分一百个,那就是一百万美元的课程。

私人方法没有这些费用。 明智地支出股东资金;尽可能私密化。

答案 2 :(得分:12)

将可见范围视为信任的内部圈子。

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

同样,在编程中,范围为您提​​供了创建不同信任圈的工具。此外,让事物变得私密/受保护,让您更好地控制正在发生的事情。例如,您可以允许可以扩展某些代码的第三方插件,但它们可以限制在可以走多远的范围内。

因此,为了概括,范围可以为您提供额外的安全级别,并使事情更加有条理。

答案 3 :(得分:10)

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

答案 4 :(得分:9)

你说有风险吗?

<?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;
    }
}

现在你可以确定,只要设置了Foo :: $ bar,就会有一个对象instanceof SomeObject

答案 5 :(得分:4)

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

这是一个人为的堆栈示例(伪代码)。

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就可以轻松破解它。

如果您只公开这些功能,则会提供其他人可以使用和信任的可靠合同。公开实施只是让它成为一件可能无人问津的事情。

答案 6 :(得分:2)

任何语言都不需要封装,但它很有用。 封装用于最大限度地减少具有最高变化传播概率的潜在依赖关系的数量,同时也有助于防止出现不一致:

简单示例:假设我们创建了一个包含四个变量的Rectangle类 - 长度,宽度,面积,周长。请注意,面积和周长是从长度和宽度得出的(通常我不会为它们制作变量),因此改变长度会改变面积和周长。

如果你没有使用正确的信息隐藏(封装),那么利用该Rectangle类的另一个程序可以在不改变区域的情况下改变长度,并且你会有一个不一致的Rectangle。如果没有封装,就可以创建长度为1,宽度为3的Rectangle,面积为32345.

使用封装,我们可以创建一个函数,如果程序想要更改矩形的长度,则该对象将适当地更新其区域和周边而不会出现不一致。

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

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

问题是封装在需要它的地方很棒,但是当它应用在不需要它的地方时很糟糕,比如需要通过一组封装来维护全局属性,因为OOP强制封装无论如何,你都被困住了。例如,对象的许多属性都是非本地的,例如,任何类型的全局一致性。在OOP中经常发生的事情是每个对象都必须编码其全局一致性条件的视图,并尽其所能来帮助维护正确的全局属性。如果您真的需要封装,这可能很有趣,以允许其他实现。但是如果你不需要它,你最终会在多个地方编写很多非常棘手的代码,基本上会做同样的事情。一切似乎都是封装的,但实际上是完全相互依赖的。

答案 7 :(得分:2)

嗯,实际上你可以让一切都公开,当你清楚说明,合同是什么,使用对象的正确方法时,它不会破坏封装。也许不是属性,但方法通常比它们必须更隐蔽。

请记住,API设计师并不是通过公开内容来打破封装。通过调用他们的应用程序中的内部方法,该类的用户可以这样做。您可以拍手试图这样做(即声明方法私有),或将责任传递给它们(例如,通过在非API方法前添加“_”)。您是否真的在乎是否有人通过使用您的图书馆来打破他的代码,而您建议他这样做?我没有。

另一方面,几乎所有内容都是私有的或最终的 - 或者在没有API文档的情况下让它们离开 - 是一种阻止可扩展性和开源反馈的方法。您的代码可以以您甚至没有想到的方式使用,当一切都被锁定时可能不是这种情况(例如,在C#中使用默认方法密封)。

答案 8 :(得分:1)

如果您不使用私有受保护抽象静态决赛,那么您可能遇到的唯一问题就是人们会认为您“不酷”界面或其他什么。这些东西就像名牌服装或Apple小工具 - 人们购买它们不是因为他们需要,而只是为了跟上他人。

是的,封装是一个重要的理论概念,但在实践中“私人”和朋友很少有意义。他们可能在Java或C#中有所作为,但在像PHP这样的脚本语言中使用“私有”或“受保护”纯粹是愚蠢的,因为封装是由编译器发明的,它不会被编译器检查。 t存在于PHP中。 More details

另请参阅this excellent response和@troelskn以及here以上的@mario评论

答案 9 :(得分:1)

可见性只是您可以使用为自己的利益,以帮助您不破坏自己的代码。如果您正确使用它,您将帮助其他人(使用您的代码)不会破坏他们自己的代码(通过不使用您的代码)。

在我看来,最简单,众所周知的例子是Singleton模式。这是一种模式,因为这是一个常见的问题。 (来自维基百科的模式的定义:

  

是记录设计问题解决方案的正式方法

维基百科中单身人士模式的定义:

  

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

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

模式的实现使用私有构造函数。如果你不把构造函数设为私有,那么任何人都可能错误地创建一个新实例,并打破只有一个实例的重点。

答案 10 :(得分:1)

您可能认为之前的答案是“理论上的”,如果您在Doctrine2实体中使用public属性,则会破坏延迟加载。

答案 11 :(得分:1)

拯救你自己!

上面有一些很好的答案,但我想补充一点。这称为principle of least privilege。凭借较少的特权,较少的实体有权破坏事物。破坏事情很糟糕。

如果您遵循最小特权原则,principle of least knowledge(或Demeter法则)和single responsibility principle并不落后。由于您编写的下载最新足球分数的课程遵循了这一原则,您必须轮询其数据而不是将其直接转储到您的界面,您将整个课程复制并粘贴到您的下一个项目中,从而节省了开发时间。节省开发时间。

如果你很幸运,你将在6个月后回到这段代码来修复一个小错误,在你从中获得gigaquads钱之后。未来的自我将因为不遵守上述原则而徒劳无功,他将成为违反principle of least astonishment的受害者。也就是说,您的错误是足球得分模型中的解析错误,但由于您没有关注LOD和SRP,您会惊讶于您正在对输出生成内联进行XML解析。生活中有更好的事情要比你自己的代码的可怕性更令人惊讶。相信我,我知道。

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