Unencapsulated means Unchangeable?

2020-03-03 09:30发布

问题:

I came across this line in Effective C++:

Public means unencapsulated, and practically speaking, unencapsulated means unchangeable, especially for classes that are widely used.Yet widely used classes are most in need of encapsulation, because they are the ones that can most benefit from the ability to replace one implementation with a better one

What does the author mean by "Public means unencapsulated, and practically speaking, unencapsulated means unchangeable"?

And how is unencapsulated unchangeable?

回答1:

The general idea is simple. If you make something public, then someone can and probably will use it. Therefore, if you change something that is public, all of the code that uses it immediately breaks. Breaking people's code is bad; it tends to lead to them not wanting to use your code anymore, since now you've forced them to rewrite all of their stuff just because you wanted to use a different type or something.

The public interface is a contract between the implementation of the class and the user of it. Changing that contract, particularly without advanced notice, is considered very rude.

If all of your code is internal, that's fine. But if it's not, if you're making a library for others to use (whether locally or just selling a library), then people are less likely to be happy about interface changes.

It isn't a matter of rules of C++; it's simply a matter of rules of interface design. Since public things are part of the interface, you must be careful about what you make public.



回答2:

Encapsulation is the idea that you can access the data member of a class only through interface methods. The effect of using a method is "hiding" the actual implementation of the data member, so that you can change it without the need to change the code that uses that class through the interface methods (provided you don't change the way they are defined).

On the other hand, if you don't use interface methods to hide the data member implementation, all your code that uses it will need to be modified in front of any change in the data member.

Say that you have a class with a vector of strings containing a list of names. If you make public that vector, then all other classes can decide to directly use it, and access the strings it contains by their index in the vector (the index acts as a key to identify the string, say).

Later, you could decide you need a map to manage all those strings (your requirement have changed). You change the data member definition to a map and your code will not compile anymore. This is the meaning of "practically unchangeable".

The "right" way to manage this through encapsulation is making the data member private and define an interface method like:

std::string getStringWithKey(int index);

this method will access the vector in the first implementation, and the map in the second case. All this in a transparent way: the code that uses the method (instead of accessing directly the data member) will not need to be modified, so you can change the data member implementation as you like at almost no cost.

This is an oversimplification, because design of interfaces is not a simple matter and interfaces also do change, but I hope it helps clarifying things.



回答3:

I guess the best answer would be given by the author. My guess is that he means that if you declare a public member and use it on many other places in your code, then it would be hard work to change all those places if you later decide to change that member.



回答4:

He is referring to data members, and he is saying that publicly exposing data members as part of the public interface means that you can never change their nature, i.e. name and type.