Sil*_*ini 36 oop visibility private protected
这是一个相当基本的OO问题,但是一段时间以来一直困扰着我.
我倾向于避免使用'private'可见性修饰符来支持我的字段和方法protected.
这是因为,一般来说,我没有看到在基类和子类之间隐藏实现的任何用法,除非我想为我的类的扩展设置特定的指导(即在框架中).对于大多数情况,我认为试图限制我的课程将由我或其他用户扩展是不利的.
但是,对于大多数人来说,private修饰符通常是定义非公共字段/方法时的默认选择.
那么,你可以列出用例private吗?总是使用私有的主要原因是什么?或者您是否也认为它过度使用?
Mac*_*cke 30
有一些共识认为,在OOP中,人们应该更喜欢构成而不是继承.这有几个原因(谷歌,如果你感兴趣),但主要部分是:
因此,如果您选择让您的课程可以继承,您应该有意识地这样做,并考虑到所有的优点和缺点.
因此,最好不要使类继承,而是通过使用其他方法确保它尽可能灵活(而不是更多).
这在大型框架中非常明显,在这种框架中,您的课程的使用超出了您的控制范围.对于你自己的小应用程序,你不会注意到这一点,但是如果你不小心的话,它(默认继承)迟早会把你咬在后面.
备择方案
组合意味着您通过显式(完全抽象)接口(虚拟或基于模板)公开可定制性.
因此,不是让Vehicle基类具有虚拟drive()函数(以及其他所有内容,例如价格整数等),而是让Vehicle类获取Motor接口对象,以及Motor接口仅暴露drive()函数.现在,您可以在任何地方添加和重复使用任何类型的电机(或多或少.:).
sup*_*cat 17
有两种情况,无论成员是protected或是private:
如果可以想象一个真实的场景,派生类可能会从访问该成员中受益,并且无法想象基类可能会从更改其行为中受益的场景,那么该成员应该protected[当然假设它是不应该公开].如果无法想象一个派生类可以从直接访问成员中获得很多好处的场景,但可以想象一下基类的未来版本可能通过更改它而受益的场景,那么它应该是private.这些案件非常明确和直截了当.
如果没有任何合理的场景,基类会从更改成员中受益,我建议人们应该倾向于实现它protected.有人会说"YAGNI"(你不需要它)的原则有利private,但我不同意.如果你期望别人继承这个班级,那么让一个成员私有不会假设"YAGNI",而是"HAGNI"(他不会需要它).除非"你"需要在课程的未来版本中更改项目的行为,否则"你"不会需要它private.相比之下,在许多情况下,您无法预测班级的消费者可能需要什么.这并不意味着人们应该在protected没有首先尝试确定改变它们的方式的情况下成员,因为YAGNI这两种决定都不适用.YAGNI适用于遇到未来需求的情况,因此现在无需处理.决定将一个成员提供给其他程序员,private或者protected暗示决定将来会提供哪种类型的潜在需求,并且难以为另一个提供.
有时这两种情况都是合理的,在这种情况下,提供两个类可能会有所帮助 - 其中一个类暴露了有问题的成员,而一个类来自那个没有的类(没有标准的惯用语是派生类隐藏成员继承自其父级,虽然声明具有相同名称但没有可编译功能且标记有Obsolete属性的新成员将具有该效果).作为所涉及权衡的一个例子,请考虑List<T>.如果类型将支持数组暴露为受保护的成员,则可以定义CompareExchangeableList<T> where T:Class包含T CompareExchangeItem(index, T T newValue, T oldvalue)将返回的成员的派生类型Interlocked.CompareExchange(_backingArray[index], newValue, oldValue); 任何预期a的代码都可以使用这种类型List<T>,但知道实例的代码CompareExchangeableList<T>可以使用CompareExchangeItem它.不幸的是,因为List<T>没有将后台数组暴露给派生类,所以不可能定义允许CompareExchange列表项但仍然可以被期望a的代码使用的类型List<T>.
尽管如此,这并不意味着暴露支持阵列完全没有成本; 尽管现有的所有实现都List<T>使用单个支持数组,但是当列表超过84K时,Microsoft可能会实现未来版本以使用多个数组,以避免与大对象堆相关的低效率.如果支持数组作为受保护成员公开,则在不破坏任何依赖该成员的代码的情况下实现此类更改是不可能的.
实际上,理想的可能是通过提供受保护的成员来平衡这些兴趣,在给定列表项索引的情况下,该成员将返回包含指示项的数组段.如果只有一个数组,则该方法将始终返回对该数组的引用,其偏移量为零,起始下标为零,长度等于列表长度.如果List<T>将数组拆分为多个部分的未来版本,该方法可以允许派生类以不具备此类访问权限的方式有效地访问数组的段[例如使用Array.Copy],但List<T>可以改变其管理其后备存储的方式打破正确编写的派生类.如果基本实现发生更改,则编写不正确的派生类可能会被破坏,但这是派生类的错误,而不是基类的错误.