In this tutorial, we’ll study access modifiers in object-oriented programming (OOP). Furthermore, we’ll go through key differences between the private and protected access modifiers.
2. Access Modifiers in OOP
In the object-oriented paradigm, access modifiers control the accessibility and security of a class, method, or attribute. We also call them access specifiers.
So, they help us define varying levels of encapsulation for each entity of interest.
We set an access modifier for each attribute and method to specify how other entities of the system can access them. Most OOP-based languages have three key access modifiers:
3. Public Access
We use the public access modifier when something is accessible from anywhere. For example, if we define a class as public in Java, we can access it from the following places:
- From anywhere in the project after importing (Global scope)
- From within the same class
- Within the same package
- Within the same package of any sub-class
So, the public has the widest scope among all the modifiers. When would we use it? For example, let’s say we have multi-module software and want each module to generate logs in a specific format. We can make the logger class or package public so that each module can access its operations to format and generate logs as per specifications.
4. Private Access
This is the most secure access level, and it maximizes encapsulation. We set an entity (class, method, attribute) as private when we want it to be accessible only from the same place where we define it.
So, a private attribute is limited to its defining class. We can’t access it outside of the class in which it’s defined. The same goes for private methods and classes.
For example, let’s say our software application uses an access key to connect to the central database for verifying security credentials. We want this access key to be as secure as possible. So, we use the private modifier to make it accessible only via a carefully designed method from the defining class.
5. Protected Access
The protected access modifier uses the inheritance level of the entity to set its accessibility to the outside world. This means that we can use the protected access modifier for an entity that we want to be visible in all the classes inheriting its defining class. In Java, however, we can access a protected entity within the defining class’s package as well.
Let’s go through an example. Let’s say we use message queues for inter-process communication between various modules of our application. Then, we can define a parent class for the message queue and set operations create_queue() and delete_queue() as protected. That way, only the classes inheriting the parent queue class will get access to these methods as they’re the only ones that need to use them. Other classes that use those child classes access those methods only indirectly, via the interfaces provided by the child classes.
We can make a class attribute, method, or constructor protected. However, we can’t mark a class protected.
6. private vs. protected
Let’s now enumerate the key differences between the private and protected access modifiers.
The biggest difference between them is when we need to use them. We make a method or an attribute private when we want to restrict its access from the outside world and want it to be accessed only from its defining class.
A good design heuristic is to make every entity private unless there is no use for it to the outside world. This helps us make our class more encapsulated, secure, and robust. That way, we can change its internals without breaking our application.
On the other hand, we have protected methods and attributes that are visible from the child classes. So, once we make a class inheritable, we have to be careful in setting what may be overridden and accessible from its subclasses and what must be opaque.
6.2. Encapsulation Level
These access modifiers have different encapsulation levels.
A private entity is more encapsulated as compared to a protected one. We use private access for cases where there is no requirement for an IS-A relationship.
On the other side of the spectrum, we use protected access for cases where there is a definite requirement for an IS-A relationship. At the same time, we want to restrict the accessibility of protected members of the parent class only to its descendant classes.
6.3. Security Implications
When we mark an attribute or a method as protected, we can induce a security bug.
Let’s say we have a class A with a protected method implement_future(). We just keep this method as a placeholder to implement some future functionality. After a few months, we realize there is no need to write any code for implement_future(). But any other person can override it and this can hamper the overall functionality.
As a solution to this, the developer must annotate all protected variables and methods properly.
6.4. Code Readability and Maintainability
Private members make the code cleaner, more readable, and highly maintainable. This is so because the private attributes and methods are confined to the defining class so we document them there. However, protected entities have to be documented at all places where we override them.
The major problem with the protected access maintenance is that it makes our system backward incompatible. Let’s say we have a class that has a protected attribute , and a protected method . Now, let and inherit . More so, we override in both these child classes. Now, we make part of our API implementation that is exposed to the external world. Thus, becomes a part of the public class’s application programming interface (API). This implies that if later we want to make changes in class , we can’t do so without breaking child classes and .
6.5. Commercial Considerations
Most commercial software restricts their design and internals. Thus, they mostly make their core components private. For example, most of the classes of Microsoft products are private.
On the other hand, open-source libraries adopt protected modifiers. This helps their users extend the functionality and provide the modified library back to the community for usage. For example, the TensorFlow library uses protected attributes and methods so that developers can extend their functionality as per their niche requirements.
7. Summary of Differences
Here’s a quick summary:
In this article, we went through three different access modifiers in object-oriented programming and enumerated the differences between private and protected access modifiers.
As a good design heuristic, it’s better to mark key entities as protected when designing big libraries or large module-based software. In the case of commercial products or monolithic projects, it is better to mark key entities as private.