信息隐藏和属性
信息隐藏是否意味着我应该尽量减少我的课程拥有的属性数量?是对的吗?我们是否倾向于使用方法将类设置为私有字段?
解决方案
声明范围内的私有内容并不能真正"隐藏"信息。
我相信隐藏信息是指通过接口将逻辑与使用者隔离,因此我们可以更改逻辑而不会影响使用者。
信息隐藏与外部类可以访问类(字段,属性)中的数据量有关。隐藏的内容越多,以后在不影响相关类(即"公共接口")的情况下更改实现就越容易。最终导致更稳定的设计。
信息隐藏意味着不要向班级的消费者公开他们不需要知道的内容。隐藏属性并用方法替换它们是没有意义的,因为属性实际上是方法的特殊类型
信息隐藏既隐藏逻辑又隐藏数据。我们应该能够从根本上进行更改,并且不会影响班级的用户。
似乎许多人从原则上理解了信息隐藏,但随后又认为所有内容的获取者和设置者/所有内容的属性就是一个例子。
艾伦·霍鲁布(Allen Holub)题为"为什么吸气剂和吸气剂是邪恶的"的引人入胜的文章可以使这个话题大开眼界。
简而言之,拥有直接获取者和安置者的私人成员不过是打扮得整整齐齐的公共成员。确实需要在层边界(UI,持久性等)处使用getter和setter,但应将它们的可见性限制在那些有合理需要调用它们的类中。
通过Public方法访问的私有字段。尽管看起来像这样愚蠢地加倍:
private int _myInt; public int MyInt { get { return _myInt; } set { _myInt = value; } }
尽管现在我们可以做到(IIRC,我的3.5知识还不完整):
public int MyInt { get; set; }
我们可能会问,为什么要使访问者提供的访问权限与原始属性的访问权限完全相同。但是通过将原始属性设为私有,如果我们决定只希望允许偶数,则可以执行以下操作:
public int MyInt { get { return _myInt; } set { _myInt = (value % 2 == 0) ? value : _myInt; } }
(注意:这不是最好的示例,因为它不会让用户知道其操作失败。)
基本上,我们永远不想将内部操作公开给我们班上的任何使用者。而我们要做的就是尽可能多地隐藏并且只暴露我们必须要做的事情。
如果外部世界不需要看到它,那么就不要显示它。我们应该尝试封装对象,以使它们失去耦合,并且外界对它们的了解足够多。
隐藏信息的目的是将对象的使用者暴露在对象内部操作方式发生的变化中。更改的可能性越大,使其远离接口的重要性就越大。这就是为什么getter和setter是常见的原因...接口发出的值可以以除类型以外的任何方式更改,而不会影响与接口使用者的合同。这也是一条通用的通用规则,即只有对象本身才可以影响其状态,因此,setter提供了一种方法来强制执行有关对象状态如何更改的契约,理想情况下也不会影响接口。我认为通常最好在私有变量中维护状态,并提供getter和setter作为它们的公共接口(当外部对象需要访问它们时),主要是因为我们始终可以选择提供某种验证或者转换如果有必要在不破坏界面的情况下进行生产。
曾经通过问"你好吗?"来进行对话,却遇到了他们的麻烦和胜利,宠物怒气和无趣的兴趣,不安全感以及也许对早餐松饼的深入审查……
...这不是信息隐藏。我们大多数人都不那样做。孩子们至少在第一次见到某个人之前就使用了他们分享的所有无关信息,以某种方式伤害或者侮辱他们……然后,他们学会了秘密和偏执,这是通往成年之路的又一步。
我们大多数人还学会用编写的代码做同样的事情,只暴露与其他代码相处的程度,但又不至于让它依赖我们的实现。这比不仅仅公开内部数据,而只是在内部数据和寒冷的外部世界之间放置访问者方法或者属性获取器/设置器,比起就"我的这个朋友"和"他的"疱疹进行对话而言,隐藏的信息要多得多。问题...
当我们开始区分接口和实现时,我们就成为问题的核心。当我们公开属性是因为它们与客户代码所期望的世界观相匹配时,而不是因为它们为它们提供了一种方便的方式来操纵实现。即使是自上而下地开发,它也很少有明确的鸿沟,而且人为的例子容易造成弊大于利:不加掩饰混淆恰好是完美接口的实现细节是完全有害的。