Should protected attributes always be banned?

2019-03-18 10:27发布

I seldom use inheritance, but when I do, I never use protected attributes because I think it breaks the encapsulation of the inherited classes.

Do you use protected attributes ? what do you use them for ?

标签: oop protected
14条回答
The star\"
2楼-- · 2019-03-18 11:00

It depends on what you want. If you want a fast class then data should be protected and use protected and public methods. Because I think you should assume that your users who derive from your class know your class quite well or at least they have read your manual at the function they going to override.

If your users mess with your class it is not your problem. Every malicious user can add the following lines when overriding one of your virtuals:

(C#)

static Random rnd=new Random();
//...
if (rnd.Next()%1000==0) throw new Exception("My base class sucks! HAHAHAHA! xD");
//...

You can't seal every class to prevent this.

Of course if you want a constraint on some of your fields then use accessor functions or properties or something you want and make that field private because there is no other solution...

But I personally don't like to stick to the oop principles at all costs. Especially making properties with the only purpose to make data members private.

(C#):

private _foo;
public foo
{
   get {return _foo;}
   set {_foo=value;}
}

This was my personal opinion.

But do what your boss require (if he wants private fields than do that.)

查看更多
疯言疯语
3楼-- · 2019-03-18 11:03

In this interview on Design by Bill Venners, Joshua Bloch, the author of Effective Java says:

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.

Short version: it breaks encapsulation but it's a necessary evil that should be kept to a minimum.

查看更多
干净又极端
4楼-- · 2019-03-18 11:04

I think protected attributes are a bad idea. I use CheckStyle to enforce that rule with my Java development teams.

查看更多
劳资没心,怎么记你
5楼-- · 2019-03-18 11:06

There are never any good reasons to have protected attributes. A base class must be able to depend on state, which means restricting access to data through accessor methods. You can't give anyone access to your private data, even children.

查看更多
做自己的国王
6楼-- · 2019-03-18 11:13

Scott Meyers says don't use protected attributes in Effective C++ (3rd ed.):

Item 22: Declare data members private.

The reason is the same you give: it breaks encapsulations. The consequence is that otherwise local changes to the layout of the class might break dependent types and result in changes in many other places.

查看更多
Root(大扎)
7楼-- · 2019-03-18 11:17

I use protected variables/attributes within base classes that I know I don't plan on changing into methods. That way, subclasses have full access to their inherited variables, and don't have the (artificially created) overhead of going through getters/setters to access them. An example is a class using an underlying I/O stream; there is little reason not to allow subclasses direct access to the underlying stream.

This is fine for member variables that are used in direct simple ways within the base class and all subclasses. But for a variable that has a more complicated use (e.g., accessing it causes side effects in other members within the class), a directly accessible variable is not appropriate. In this case, it can be made private and public/protected getters/setters can be provided instead. An example is an internal buffering mechanism provided by the base class, where accessing the buffers directly from a subclass would compromise the integrity of the algorithms used by the base class to manage them.

It's a design judgment decision, based on how simple the member variable is, and how it is expected to be so in future versions.

Encapsulation is great, but it can be taken too far. I've seen classes whose own private methods accessed its member variables using only getter/setter methods. This is overkill, since if a class can't trust its own private methods with its own private data, who can it trust?

查看更多
登录 后发表回答