是否应该始终禁止保护属性?
我很少使用继承,但是当我这样做时,我从不使用受保护的属性,因为我认为它破坏了继承类的封装。
我们是否使用受保护的属性?你用它们做什么?
解决方案
回答
我们可能需要它们来获取静态(或者"全局")属性,以便子类或者同一程序包中的类(如果是关于Java的)能够从中受益。
那些表示某种"常量值"的静态最终属性很少具有getter函数,因此在这种情况下,受保护的静态最终属性可能有意义。
回答
我不在Java中使用受保护的属性,因为它们仅在其中受到程序包保护。但是在C ++中,我将在抽象类中使用它们,允许继承的类直接继承它们。
回答
C#:
我对希望基类覆盖的抽象方法或者虚拟方法使用了protected。如果基类可以调用该方法,我也将其设为受保护的方法,但我不希望在类层次结构之外调用该方法。
回答
从来没有任何很好的理由拥有受保护的属性。基类必须能够依赖状态,这意味着限制通过访问器方法访问数据。我们不能授予任何人甚至孩子访问私人数据的权限。
回答
通常,不,我们真的不想使用受保护的数据成员。如果我们编写API,这是双重事实。一旦有人从班级继承下来,我们将永远无法真正进行维护,也无法以某种奇怪的,有时是疯狂的方式破坏他们。
回答
我用它们。简而言之,如果要共享某些属性,这是一个好方法。当然,我们可以为它们编写set / get函数,但是如果没有验证,那有什么意义呢?它也更快。
考虑一下:我们有一个类,它是基类。它具有许多我们不想在子对象中使用的属性。我们可以为每个函数编写一个get / set函数,也可以只对其进行设置。
我的典型示例是文件/流处理程序。我们想访问处理程序(即文件描述符),但想将其从其他类中隐藏。这比为其编写set / get函数要容易得多。
回答
我认为保护属性不是一个好主意。我使用CheckStyle与我的Java开发团队一起执行该规则。
回答
一般来说,是的。受保护的方法通常更好。
在使用中,通过为类的所有子级共享的对象使用受保护的最终变量,可以实现一定程度的简化。我总是建议不要将其与基元或者集合一起使用,因为无法为这些类型定义合同。
最近,我开始将我们使用基元和原始集合所做的工作与我们使用格式良好的类进行的工作分开。基元和集合应始终是私有的。
另外,当公共成员变量最终赋值时,它们偶尔会公开,它们是格式灵活,不太灵活的类(同样,不是原语或者集合)。
这不是愚蠢的捷径,我非常认真地考虑了一下,并决定了公开最终变量和获取对象之间绝对没有区别。
回答
斯科特·迈耶斯(Scott Meyers)说,不要在有效C ++中使用受保护的属性(第三版):
Item 22: Declare data members private.
原因与我们给出的相同:它破坏了封装。结果是,否则,对类布局的局部更改可能会破坏从属类型,并导致许多其他位置的更改。
回答
我最近从事的一个项目是"受保护"成员,这是一个很好的主意。类hiearchy是这样的:
[+] Base | +--[+] BaseMap | | | +--[+] Map | | | +--[+] HashMap | +--[+] // something else ?
该基地实现了一个std :: list,但没有别的。禁止用户直接访问列表,但是由于Base类不完整,因此无论如何都依赖于派生类来实现对列表的间接访问。
间接访问可能至少来自两种方式:std :: map和stdext :: hash_map。两种映射的行为方式相同,但hash_map需要将Key设为可哈希(在VC2003中,可转换为size_t)。
因此,BaseMap将TMap实施为模板类型,该类型是类似于地图的容器。
Map和HashMap是BaseMap的两个派生类,一个是std :: map上的BaseMap专用,另一个是stdext :: hash_map上的BaseMap。
所以:
- Base不能这样使用(没有公共访问者!),仅提供了共同的功能和代码
- BaseMap需要容易地读/写到std :: list
- Map和HashMap需要对BaseMap中定义的TMap进行轻松的读/写访问。
对我而言,唯一的解决方案是对std :: list和TMap成员变量使用protected。我没有办法将这些"私有"设置为私有,因为无论如何我还是会通过读/写访问器公开它们的全部或者几乎所有功能。
最后,我想如果我们将类划分为多个对象,则每个派生类都会在其父类中添加所需的功能,只有最派生的类才真正可用,然后采取保护措施。 "受保护成员"是一个阶级,因此几乎不可能"破坏"这一事实。
但是否则,应尽可能避免受保护(即:默认情况下使用private,而在必须公开该方法时使用public)。
回答
在有效的Java技术的作者Joshua Bloch的Bill Venners对设计的采访中,他说:
Trusting Subclasses Bill Venners: Should I trust subclasses more intimately than non-subclasses? For example, do I make it easier for a subclass implementation to break me than I would for a non-subclass? In particular, how do you feel about protected data? Josh Bloch: To write something that is both subclassable and robust against a malicious subclass is actually a pretty tough thing to do, assuming you give the subclass access to your internal data structures. If the subclass does not have access to anything that an ordinary user doesn't, then it's harder for the subclass to do damage. But unless you make all your methods final, the subclass can still break your contracts by just doing the wrong things in response to method invocation. That's precisely why the security critical classes like String are final. Otherwise someone could write a subclass that makes Strings appear mutable, which would be sufficient to break security. So you must trust your subclasses. If you don't trust them, then you can't allow them, because subclasses can so easily cause a class to violate its contracts. As far as protected data in general, it's a necessary evil. It should be kept to a minimum. Most protected data and protected methods amount to committing to an implementation detail. A protected field is an implementation detail that you are making visible to subclasses. Even a protected method is a piece of internal structure that you are making visible to subclasses. The reason you make it visible is that it's often necessary in order to allow subclasses to do their job, or to do it efficiently. But once you've done it, you're committed to it. It is now something that you are not allowed to change, even if you later find a more efficient implementation that no longer involves the use of a particular field or method. So all other things being equal, you shouldn't have any protected members at all. But that said, if you have too few, then your class may not be usable as a super class, or at least not as an efficient super class. Often you find out after the fact. My philosophy is to have as few protected members as possible when you first write the class. Then try to subclass it. You may find out that without a particular protected method, all subclasses will have to do some bad thing. As an example, if you look at AbstractList, you'll find that there is a protected method to delete a range of the list in one shot (removeRange). Why is that in there? Because the normal idiom to remove a range, based on the public API, is to call subList to get a sub-List, and then call clear on that sub-List. Without this particular protected method, however, the only thing that clear could do is repeatedly remove individual elements. Think about it. If you have an array representation, what will it do? It will repeatedly collapse the array, doing order N work N times. So it will take a quadratic amount of work, instead of the linear amount of work that it should. By providing this protected method, we allow any implementation that can efficiently delete an entire range to do so. And any reasonable List implementation can delete a range more efficiently all at once. That we would need this protected method is something you would have to be way smarter than me to know up front. Basically, I implemented the thing. Then, as we started to subclass it, we realized that range delete was quadratic. We couldn't afford that, so I put in the protected method. I think that's the best approach with protected methods. Put in as few as possible, and then add more as needed. Protected methods represent commitments to designs that you may want to change. You can always add protected methods, but you can't take them out. Bill Venners: And protected data? Josh Bloch: The same thing, but even more. Protected data is even more dangerous in terms of messing up your data invariants. If you give someone else access to some internal data, they have free reign over it.
简短的版本:它破坏了封装,但这是一个必须避免的恶疾,应将其降至最低。
回答
这取决于我们想要什么。如果要使用快速类,则应保护数据并使用受保护的公共方法。
因为我认为我们应该假设派生自我们班级的用户非常了解班级,或者至少他们已经阅读了将要覆盖的功能的手册。
如果用户不喜欢班级,那不是问题。每个恶意用户在覆盖一个虚拟机时都可以添加以下行:
(C#)
static Random rnd=new Random(); //... if (rnd.Next()%1000==0) throw new Exception("My base class sucks! HAHAHAHA! xD"); //...
我们不能封闭每个班级来防止这种情况。
当然,如果我们希望对某些字段进行约束,则可以使用访问器函数或者属性或者所需的东西并将其设为私有,因为没有其他解决方案...
但是,我个人不愿意不惜一切代价遵守oop原则。特别是使属性的唯一目的是使数据成员私有。
(C#):
private _foo; public foo { get {return _foo;} set {_foo=value;} }
这是我个人的看法。
但是,请执行我们老板的要求(如果他想要私有字段,则可以这样做)。
回答
我在基类中使用受保护的变量/属性,我知道我不打算将其更改为方法。这样,子类就可以完全访问其继承的变量,并且没有(人工创建的)通过getter / setter方法访问它们的开销。一个示例是使用基础I / O流的类。没有什么理由不允许子类直接访问基础流。
这对于在基类和所有子类中以直接简单的方式使用的成员变量很好。但是对于具有更复杂用途的变量(例如,对其进行访问会导致该类中其他成员的副作用),直接访问变量是不合适的。在这种情况下,可以将其设为私有,而可以提供公共/受保护的吸气剂/设置器。一个示例是基类提供的内部缓冲机制,其中直接从子类访问缓冲区将损害基类用于管理它们的算法的完整性。
这是一个设计判断决定,取决于成员变量的简单程度以及将来版本中的期望程度。
封装很棒,但是可能太过分了。我见过一些类,它们的私有方法仅使用getter / setter方法访问其成员变量。这太过分了,因为如果类不能用自己的私有数据信任自己的私有方法,那么谁可以信任谁?