OOP
Definition
Object-Oriented Programming is a way of writing code that allows you to create different objects from a common object. The common object is usually called a blueprint while the created objects are called instances.
Building blocks of OOP:
Classes are user-defined data types, creating a blueprint for the structure of methods and attributes.
Objects are instances of classes created with specific data
Methods represent behaviors (might return information about an object, or update an object’s data).
Attributes are the information that is stored
The four pillars of OOP:
Inheritance: child classes inherit data and behaviors from the parent class
Encapsulation: containing information in an object, exposing only selected information
Abstraction: only exposing high-level public methods for accessing an object
Polymorphism: many methods can do the same task
Main concepts
Encapsulation
Abstraction
Inheritance
Polymorphism
Dependency injection
SOLID
Encapsulation
Encapsulation means containing all important information inside an object, and only exposing selected information to the outside world. Attributes and behaviors are defined by code inside the class template.
Then, when an object is instantiated from the class, the data and methods are encapsulated in that object. Encapsulation hides the internal software code implementation inside a class, and hides internal data of inside objects.
Encapsulation adds security. Attributes and methods can be set to private, so they can’t be accessed outside the class. To get information about data in an object, public methods & properties are used to access or update data.
Levels of security in JS:
Public: Access to all code in the program
Private: Access to only members of the same class
Protected: Access to members of the same class and its derived classes
JavaScript has private and protected properties and methods. Protected Fields are prefixed with a _
; private fields are prefixed with a #
. Protected fields are inherited, private ones aren’t.
The benefits of encapsulation are summarized here:
Adds security: Only public methods and attributes are accessible from the outside
Protects against common mistakes: Only public fields & methods accessible, so developers don’t accidentally change something dangerous
Protects IP: Code is hidden in a class, only public methods are accessible by the outside developers
Supportable: Most code undergoes updates and improvements
Hides complexity: No one can see what’s behind the object’s curtain!
Abstraction
Abstraction means that the user interacts with only selected attributes and methods of an object. Abstraction uses simplified, high-level tools, to access a complex object.
Using simple things to represent the complexity
Hide complex details from a user
Abstraction is using simple classes to represent complexity. Abstraction is an extension of encapsulation. Abstraction also serves an important security role. By only displaying selected pieces of data, and only allowing data to be accessed through classes and modified through methods, we protect the data from exposure.
The benefits of abstraction are summarized below:
Simple, high-level user interfaces
Complex code is hidden
Security
Easier software maintenance
Code updates rarely change the abstraction
An abstract class is made of abstract methods. The abstract methods are only declared, however, not implemented. When a subclass needs to use the methods, it needs to implement those methods.
The differences between interfaces and abstract classes:
An abstract class can support both abstract and non-abstract methods. However, the interface allows only abstract methods.
In the case of an abstract class, both final and non-final variables are supported. However, the interface has variables that are, by default, defined as final.
The abstract class can have private, and public attributes, but interfaces have attributes as public by default.
Encapsulation vs Abstraction
While both are OOP concepts related to data hiding, they are quite different from each other. Abstraction also relates to hiding like encapsulation, but while the former hides complexity, the latter keeps the data it encapsulates by controlling access to them. Abstraction refers to the concept of representing only the necessary features by hiding the irrelevant details to reduce the complexity of an application thereby increasing efficiency. Encapsulation, on the other hand, refers to the concept of hiding all the internal mechanics of a program in order to shield the information from unwanted access. It binds the data and information together into a single component by restricting access to other components.
Differences
Differences in “ Definition” of Abstraction and Encapsulation – Abstraction is a fundamental OOP concept which emphasizes on all the essential aspects of an object by hiding the irrelevant details to increase efficiency and eliminate complexity. Encapsulation, on the other hand, is a data hiding mechanism which wraps the data and information in a capsule to restrict access from the outside world.
Differences in “Functionality” of Abstraction and Encapsulation– Abstraction is a data hiding mechanism which highlights only the essential features to make complex programs simpler, while encapsulation, on the other hand, is a method of binding data and codes into a single entity. The idea is to shield the implementation details from external access.
Differences in “Implementation” of Abstraction and Encapsulation – Abstraction is implemented using abstract class and interface, while encapsulation is implemented using access modifiers. Five types of modifiers are used to encapsulate data: Private, Public, Protected.
Differences in “Concept” of Abstraction and Encapsulation– The idea behind abstraction is to focus on what rather than how. Encapsulation hides the internal mechanics of how. For example, when you drive a car, you know exactly what the brake pedal does but you may not know the whole mechanism behind it because the data is encapsulated.
Differences in “Example” of Abstraction and Encapsulation – Let’s take an example of a smartphone. You know what it does but you may not know how it does what it does. You only care about the display screen and keypad buttons rather than worrying about its inner circuitry. Here, smartphone is an abstract where the inner implementation details are encapsulated.
Abstraction
Encapsulation
It deals with only the relevant details by hiding the irrelevant ones to reduce complexity thereby increasing efficiency.
It binds the data and information together into a single entity to protect the data from external sources.
It refers to the idea of hiding data which is not required for presentation purposes.
It hides the data and code in order to restrict unwanted access.
It focuses on what rather than how.
It hides the internal mechanics of how it does something.
It hides the unnecessary details on the design level.
It also hides the details but on the implementation level.
Information and data is separated from the relevant data.
Information is hidden inside a capsule for close access.
It deals with ideas rather than events.
The idea is to protect the data from the outside world.
It’s implemented using abstract class and interface.
It’s implemented using protected, private, and package-private access modifiers.
Inheritance
Inheritance allows classes to inherit features of other classes. Inheritance supports reusability.
If basic attributes and behaviors are defined in a parent class, child classes can be created extending the functionality of the parent class, and adding additional attributes and behaviors.
The benefits of inheritance are programs can create a generic parent class, and then create more specific child classes as needed. This simplifies overall programming, because instead of recreating the structure of the parent class multiple times, child classes automatically gain access to functionalities within their parent class.
In JavaScript, inheritance is also known as prototyping. A prototype object acts as a template for another object to inherit properties and behaviors from. There can be multiple prototype object templates, creating a prototype chain.
Polymorphism
Polymorphism means designing objects to share behaviors. Using inheritance, objects can override shared parent behaviors, with specific child behaviors. Polymorphism allows the same method to execute different behaviors in two ways:
method overriding: Runtime polymorphism uses method overriding. In method overriding, a child class can provide a different implementation than its parent class
method overloading: Compile Time polymorphism uses method overloading. Methods or functions may have the same name, but a different number of parameters passed into the method call. Different results may occur depending on the number of parameters passed in.
The benefits of Polymorphism are:
Objects of different types can be passed through the same interface
Method overriding
Method overloading
Dependency injection
dependency injection is a technique whereby one object (or static method) supplies the dependencies of another object. A dependency is an object that can be used (a service).
Transferring the task of creating the object to someone else and directly using the dependency is called dependency injection.
There are basically three types of dependency injection:
constructor injection: the dependencies are provided through a class constructor.
setter injection: the client exposes a setter method that the injector uses to inject the dependency.
interface injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.
The dependency injection’s responsibility is:
Create the objects
Know which classes require those objects
And provide them all those objects
Benefits of using DI:
Helps in Unit testing.
Boilerplate code is reduced, as initializing of dependencies is done by the injector component.
Extending the application becomes easier.
Helps to enable loose coupling, which is important in application programming.
Disadvantages of DI:
It’s a bit complex to learn, and if overused can lead to management issues and other problems.
Many compile-time errors are pushed to run-time.
Dependency injection frameworks are implemented with reflection or dynamic programming. This can hinder use of IDE automation, such as “find references”, “show call hierarchy” and safe refactoring.
SOLID
SOLID stands for:
S - Single-responsibility Principle
O - Open-closed Principle
L - Liskov Substitution Principle
I - Interface Segregation Principle
D - Dependency Inversion Principle
Single-responsibility Principle (SRP): a class should have one and only one reason to change, meaning that a class should have only one job.
Example: (Container/presentational components in React)
Open-closed Principle (S.R.P.): objects or entities should be open for extension but closed for modification.
You should strive to write code that doesn’t have to be changed every time the requirements change.
Example: (don't hardcode something in React components, just let it be configured by props), (use the composition of small components instead of monolith JSX).
Liskov Substitution Principle: every subclass or derived class should be substitutable for their base or parent class.
The Liskov Substitution Principle means that you can inherit from a base class as long as you conform to the standards that it sets, such as having the same method name and parameters, you do not specify any deeper conditions that must be fulfilled, you return the same type that the base method does and that any Exception that is thrown must match the ones thrown by the base method.
Using TypeScript, we can easily swap objects and functions that share the same contract, without breaking the functionality of the application.
Example: (let's say we have a set of Error classes inherited from the base Error class, and we have a logger that log these errors, to follow this principle we should have the same interface for all the Errors to give the ability to the logger log any types of errors).
Interface segregation principle: a client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.
This means that the methods of a large interface can be broken up into groups of methods. If a client does not need a method then the client should not know about the method / should not have to implement it.
Example: (Pass to the child component only the props required in this component instead of passing a full object from the upper level)
Dependency inversion principle: entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions.
Example: (Container component has fetching logic and depend on 'fetch' function, we should invert dependencies to follow this principle, move fetch logic to the separate service and pass this service as a prop to the container, so that our container become independent on concrete implementation of 'fetch')
Last updated
Was this helpful?