For convenience, we’ll use the word “type” in this section to
refer to classes and traits generically, as opposed to referring to
type declarations. We’ll include those when we
use the term “member” generically,
unless otherwise indicated.
Most object-oriented languages have constructs to constrain the visibility (or scope) of type and type-member declarations. These constructs support the object-oriented form of encapsulation, where only the essential public abstraction of a class or trait is exposed and implementation information is hidden from view.
You’ll want to use public visibility for anything that users of your classes and objects should see and use. Keep in mind that the set of publicly visible members form the abstraction exposed by the type, along with the type’s name itself.
The conventional wisdom in object-oriented design is that fields should be private or protected. If access is required, it should happen through methods, but not everything should be accessible by default. The virtue of the Uniform Access Principle (see When Accessor Methods and Fields Are Indistinguishable: The Uniform Access Principle) is that we can give the user the semantics of public field access via either a method or direct access to a field, whichever is appropriate for the task.
The art of good object-oriented design includes defining minimal, clear, and cohesive public abstractions.
There are two kinds of “users” of a type: derived types, and code that works ...