封装聚合/组合
关于封装的维基百科文章指出:
“封装还通过防止用户将组件的内部数据设置为无效或不一致的状态来保护组件的完整性”
我在论坛上开始了关于封装的讨论,其中我询问是否您应该始终在 setter 和/或 getter 内部克隆对象,以保留上述封装规则。我认为,如果您想确保主对象内部的对象不会在主对象外部被篡改,您应该始终克隆它。
一位讨论者认为,在这个问题上应该区分聚合和组合。基本上我认为他是这样的:
- 如果您想返回一个属于组合一部分的对象(例如,矩形的点),请克隆它。
- 如果要返回属于聚合一部分的对象(例如,作为 UserManager 一部分的 User),只需返回它而不破坏引用即可。
这对我来说也很有意义。但现在我有点困惑了。并想听听您对此事的看法。
严格来说,封装是否总是要求克隆?
PS.:我用 PHP 编程,其中资源管理可能更相关,因为它是一种脚本语言。
The Wikipedia article about encapsulation states:
"Encapsulation also protects the integrity of the component, by preventing users from setting the internal data of the component into an invalid or inconsistent state"
I started a discussion about encapsulation on a forum, in which I asked whether you should always clone objects inside setters and/or getters as to preserve the above rule of encapsulation. I figured that, if you want to make sure the objects inside a main object aren't tampered with outside the main object, you should always clone it.
One discussant argued that you should make a distinction between aggregation and composition in this matter. Basically what I think he ment is this:
- If you want to return an object that is part of a composition (for instance, a Point of a Rectangle), clone it.
- If you want to return an object that is part of aggregation (for instance, a User as part of a UserManager), just return it without breaking the reference.
That made sense to me too. But now I'm a bit confused. And would like to have your opinions on the matter.
Strictly speaking, does encapulation always mandate cloning?
PS.: I program in PHP, where resource management might be a little more relevant, since it's a scripted language.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,事实并非如此。
您提到的人可能混淆了对象状态的保护与对象实现细节的保护。
请记住这一点:封装是一种提高代码灵活性的技术。封装良好的类可以更改其实现而不影响其客户端。这就是封装的本质。
假设有以下类:
现在,该类的封装性较低。您可以说方法 getEmployees 破坏了封装,因为通过返回类型 List,您无法再在不影响类的客户端的情况下更改此实现细节。例如,我无法在不影响客户端代码的情况下更改它,例如 Map 集合。
通过克隆对象的状态,您可能会改变客户端的预期行为。这是解释封装的一种有害方式。
人们可以说上面的代码改进了封装,因为现在 addEmployee 是唯一可以修改内部 List 的地方。因此,如果我有一个设计决定,将新的员工项目添加到列表的头部而不是尾部。我可以进行此修改:
但是,这只是封装的一小部分增量,但代价却很大。您的客户给人的印象是可以接触到员工,但实际上他们只有一份副本。因此,如果我想更新员工 John Doe 的电话号码,我可能会错误地访问 Employee 对象,并期望在下次调用 PayRoll.getEmployees 时反映更改。
具有更高封装性的实现将执行如下操作:
现在,如果我想更改映射的列表,我可以自由地执行此操作。
此外,我并没有破坏客户可能期望的行为:当从 PayRoll 修改 Employee 对象时,这些修改不会丢失。
我不想过多地扩展自己,但请告诉我这是否清楚。我很乐意继续提供更详细的示例。
No, it does not.
The person you mention is probably confusing the protection of the state of an object with the protection of the implementation details of an object.
Remember this: Encapsulation is a technique to increase the flexibility of our code. A well encapsulated class can change its implementation without impacting its clients. This is the essence of encapsulation.
Suppose the following class:
Now, this class has low encapsulation. You can say the method getEmployees breaks encapsulation because by returning the type List you can no longer change this detail of implementation without affecting the clients of the class. I could not change it for instance for a Map collection without potentially affecting client code.
By cloning the state of your object, you are potentially changing the expected behavior from clients. This is a harmful way to interpret encapsulation.
One could say the code above improves encapsulation in the sense that now addEmployee is the only place where the internal List can be modified from. So If I have a design decision to add the new Employee items at the head of the List instead of at the tail. I can do this modification:
However, that is a small increment of the encapsulation for a big price. Your clients are getting the impression of having access to the employees when in fact they only have a copy. So If I wanted to update the telephone number of employee John Doe I could mistakenly access the Employee object expecting the changes to be reflected at the next call to to the PayRoll.getEmployees.
A implementation with higher encapsulation would do something like this:
Now, If I want to change the List for a Map I can do so freely.
Furthermore, I am not breaking the behavior the clients are probably expecting: When modifying the Employee object from the PayRoll, these modifications are not lost.
I do not want to extend myself too much, but let me know if this is clear or not. I'd be happy to go on to a more detailed example.
不,封装只是要求通过创建状态的单个访问点来控制状态的能力。
例如,如果您想要封装类中的一个字段,则可以创建一个公共方法,该方法将成为获取该字段包含的值的单个访问点。封装就是围绕该字段创建单个访问点的过程。
如果您希望更改该字段值的返回方式(克隆等),您可以随意这样做,因为您知道您控制着该字段的单一途径。
No, encapsulation simply mandates the ability to control state by creating a single access point to that state.
For example if you had a field in a class that you wanted to encapsulate you could create a public method that would be the single access point for getting the value that field contains. Encapsulation is simply this process of creating a single access point around that field.
If you wish to change how that field's value is returned (cloning, etc.) you are free to do so since you know that you control the single avenue to that field.