Objects or modules should have high cohesion internally, and loose coupling externally.Or something like that. The idea being, if you have designed your object correctly, it will be filled with highly-related things, internal to itself. That's high cohesion (or is it "coherence"?).
Loose coupling, on the other hand, means that you can do useful work with
the object, with only a few member functions operating on it. External
access to the object needs to know almost nothing about the internals of the
class. You should aim to let an external function do what it needs to do,
with a minimum of calls.
Note: That does NOT mean "1 function with a 10-member struct is
better than 10 functions with 1 data-argument each"
If you find you are making a lot of the internals of an object visible, or directly changable by outside folks, then you most likely have either designed your object poorly, or have made the wrong choice of objects. Sometimes, there are multiple ways to break a program down into object. Not all of them will be as efficient as others.
An extreme example:
Let's say for some reason, you have to have representations of elephants, and oranges. Your first impulse might be to make a object class "Thing". "Thing" would then have special status queries, "isElephant()", and "isOrange()". It might then have further operators "ThingElephantFeed()", and "ThingOrangePeelit()".
This would certainly work. But it is very poor design. Firstly, it requires the programmer to know what this object "really" was. After that, the programmer uses the object in completely different ways.
There is no reason in this case to make an elephant, and an orange, share a common class. It might make more sense to have an Animal class, and a Food class. Then Animal would have "Feed()", and Food would have "ShedWrapping()".
Once again, if you find yourself using a single object type, in vastly different ways, for different invocations, you probably should not be using a single object type in the first place.
Next section: A Game-Plan