The notion of a package is related to the notion of abstract data types. A data type, e.g. Real, is a data structure together with operations on that data structure. An abstract data type is just like an ordinary data type with definitions of data and operations. That together with a method for collecting the implementations of the operations in one place and hiding the details of those implementations.
As an example, consider the package ComplexNumbers below which contains a data structure declaration, the record Complex, and associated operations such as Add, Multiply, MakeComplex, etc. Adding the word encapsulated to the package keeps the package well structured as well as being easier to understand and maintain.
In the ComplexUser class below, both the type Complex as well as the operations Multiply and Add are referenced by prefexing them with the package name ComplexNumbers.
The type Complex must be made available for allocation and initialization of variables of that type, e.g the variables a, b, z and w in ComplexUser. It would not work if you declared x and y protected in the variables Complex since then these fields would not be available for the implementation of Add and Multiply, etc. However, by declaring the operations on Complex inside the class Complex itself, as in the package ComplexNumbersA further below, these fields can be accessed even if they are protected.
We can increase the degree of data abstaction by using the function MakeComplex for initialization instead of modifiers, e.g. as in ComplexUser2 below, thus avoiding exposing the fields x and y.
In ComplexNumbersA the implementation details of the Complex data structure are hidden since its data fields are protected.