如果我们可以通过 setter 和 getter 访问私有成员,那么私有有什么用?
5 回答
您需要私有来强制执行封装。将某些东西的实现与接口分开是面向对象编程的基本范式之一。这减少了不同程序部分之间的耦合,从长远来看,使其更易于维护。
举个例子:
class toto {
private String someThing;
public String getSomething();
public void setSomething(String Something);
}
如果您在上面进行更改以简单地将 someThing 公开,请确保您的代码更少,但是如果有一天 someThing 需要更改为更复杂的对象以获得某些新功能,而旧代码仍然可以与字符串一起正常工作,那么您需要更改一切。通过隔离 someThing 的内部表示,您可以更轻松地发展您的系统
class toto {
private ComplexSomeThing someThing;
public String getSomething(){ someThing.toString();}
public void setSomething(String something){ something = new ComplexSomeThing(something);}
public ComplexSomeThing (getComplexSomething();
public void setComplexSomething(ComplexSomething someThing);
}
还有其他原因使封装成为一件好事(tm),这只是一个愚蠢的例子来说明这一点。
编辑现在关于使用受保护与私有或使用类似于某些语言(Delphi,C#)中的属性而不是getter和setter(如Java)的概念存在一些争论。受保护而不是私有将允许客户更轻松地更改代码,但它确实会更多地暴露系统的内部结构,因此需要在 API 的可用性和可维护性之间寻求平衡。然而,封装的基本原理仍然存在。无论选择何种选项,仍然需要公开一致且处于同一抽象级别的功能,并隐藏有关如何完成此操作的血腥细节。
对我来说,争论不是要宣布对私有的圣战,而是要找到一种方法来提供可扩展性和灵活性,同时又不破坏 API 的连贯性。
如果您想进一步挖掘,这里有一些关于私有的 有趣阅读。但是我必须强调,在形成对私有的看法之前,您应该真正掌握封装和多态的概念,它们表面上的简单性确实隐藏了一些微妙的复杂性。
没有人强迫你为每个变量都输入 getter 和 setter。事实上,对每个变量盲目地使用私有成员 + 虚拟 getter 和 setter 是没有意义的,尽管许多“面向对象的封装”教程出于某种原因一直这样做。一方面,从并发的角度来看,这种封装不是封装。
因为 getter 和 setter 可以充当代理。他们这样做是为了让您可以隐藏类的实际内部,只让外部类通过方法访问数据。允许您随心所欲地对待班级的内部人员。
仅仅因为你的 getter/setter 被命名getName()
并且你的属性被调用name
,并不意味着它总是这样。
如果您想将变量更改为fullName
. 如果您直接访问公共变量,则更改会破坏很多代码。相反,您可以简单地重新映射getName()
从中检索数据的位置。
我最好的例子之一是我自己的 URL 类,我允许在其中创建和操作 URL。如果要设置方案,可以获取$obj->setScheme()
. 但是,您不知道我是否在每次更改 URL 时手动创建字符串,是否将它们存储为单独的部分。这给了我灵活性,因为我可以随心所欲地存储您的数据。
此外,我可以在存储数据之前对其进行操作。在我的 URL 类中,我假设所有方案和主机名都是小写的。我可以通过将保存的所有字符串转换setHost()
为小写,然后存储它们来标准化它。如果我使用公共变量,您将不得不假设放入数据的客户端正确地存储了它。
他们还可以验证传入的信息以确保它是有效数据,如果不是则导致错误。
我认为您真正想了解的是为什么我们使用带有私有支持字段的公共属性,而不仅仅是使用公共字段。像这样的SO有几个问题;这是一个:
我认为到目前为止你有很好的答案(信息隐藏等等)。只是想添加一个关于使用 setter 的建议。
正如您所提到的,使用访问器会使私有变量变得毫无意义,并且在某些环境中,使用 getter 和 setter 的性能后果只会使它变得毫无价值。
另一方面,如果你没有这样的顾虑,我认为使用 getter 并没有那么糟糕,但在使用 setter 之前你应该三思而后行。它们使您的对象可变,这在并发环境中尤其难以维护。