OOP Principles For Dummies

tamerlang

Tamerlan Gudabayev

Posted on March 21, 2021

OOP Principles For Dummies

I don't have much experience but been in a couple of interviews.

They seem to always ask the same cliche questions.

For example:

Where do you see yourself in five years?

I usually have answers prepared beforehand, for these types of questions.

But there is one question, that I know will come up and I keep messing it up.

It is:

What are the main principles of Object-Oriented Programming?

It's pretty much a universal question, talked about in all sorts of technical interviews, from junior to senior. Interviewers ask this type of question because it is an easy way to gauge the interviewee's experience and level of understanding.

It helps to tell three things:

  1. Did the interviewee prepare for the interview?

    If you hear an answer immediately, it's usually a good sign.

  2. Does the interviewee think properly before he writes code?

    Understanding and applying the principles of OOP shows that the candidate is beyond the point of hack and slash coding. He doesn't just copy code from the internet, he has structure in his code and way of thinking.

  3. Is the interviewee understanding deep or shallow?

    This is a very open-ended question, you can go as shallow or as deep as you can. Bonus point if you go deep.

Alt Text

The four principles object-orientated programming are encapsulation, abstraction, inheritance, and polymorphism.

I know it sounds very intimidating but trust me, it's not.

It's much simpler, and that's why I want to give you simple, straight-to-the-point explanations with examples on each.

Encapsulation

Encapsulation binds data and it's related methods together within a class. It also protects the data by making fields private and giving access to them only through their related methods.

Imagine we have a small program.

It has a few objects which talk to each other, within the rules defined in the program.

Encapsulation is achieved when each object keeps its state private meaning that no outside class can directly change it. Instead, they can only call a list of public function — called methods.

Before we move on we have introduced some keywords which you may be confused about, let me explain:

  1. State: The state represents the data (value) of an object. Suppose a bank account is an object then Account Number, Amount, etc... will be the states of my bank account.
  2. Private: Data that is can only be accessed within the class.
  3. Protected: Data that can only be accessed within the class, and it's subclasses.
  4. Public: Data or functions (methods) which can be accessed outside of the class.

Violation of Encapsulation

Imagine that we have a single-player role-playing game with a class that manages quests called Quest.



public class Quest {
    // possible options for status
    private static final int NOT_PICKED = 0;
    private static final int PICKED = 1;
    private static final int COMPLETED = 2;

    // state
    public String title;
    public int reward;
    public int status;

    // Constructor
    public Quest(String title, int reward, int status){
        this.title = title;
        this.reward = reward;
        this.status = status;
    }

    // Other behavior
}


Enter fullscreen mode Exit fullscreen mode

Our client code will look something like this:



public static void client() {
    Quest quest = new Quest('Goblin Slaying', 190, 3);
}


Enter fullscreen mode Exit fullscreen mode

Imagine that one of the players got access to this client, and wanted to cheat by changing the game status and reward.



public static void client() {
    Quest quest = new Quest('Goblin Slaying', 190, 3);
    quest.reward = 1000000000;
    quest.status = 5;
}


Enter fullscreen mode Exit fullscreen mode

Right now this code is valid, because our variables are publicly accessible. Another problem here is that our "hacker" set the status to 5 which doesn't exist, and thus our game breaks.

Fixing Our Example

The way to fix this is to simply make all our variables private and only accessible through their respective methods.



public class Quest {
    private static final int NOT_PICKED = 0;
    private static final int PICKED = 1;
    private static final int COMPLETED = 2;

    private String title;
    private int reward;
    private int status;

    public Quest(String title, int reward, int status){
        this.title = title;
        this.reward = reward;
        this.status = status;
    }

    public String getTitle() {
        return title;
    }

    public int getReward() {
        return reward;
    }

    public int getStatus() {
        return status;
    }

    public void setQuestNotPicked(){
        this.status = NOT_PICKED;
    }

    public void setQuestPicked(){
        this.status = PICKED;
    }

    public void setQuestCompleted(){
        this.status = COMPLETED;
    }

    // other behavior

}


Enter fullscreen mode Exit fullscreen mode

With these changes now, we cannot change the reward and title. But we can get them through their respective functions.

Finally, our code is "hacker" safe.

Benefits of Encapsulation

  • Encapsulation protects an object from unwanted access by clients.
  • Encapsulation allows access to a level without revealing the complex details below that level.
  • It reduces human errors.
  • Simplifies the maintenance of the application
  • Makes the application easier to understand.

Tips on encapsulation

For the best encapsulation, object data should almost always be restricted to private or protected. If you choose to set the access level to public, make sure you understand the consequences of the choice.

Abstraction

Abstraction is the concept of object-oriented programming that "shows" only essential attributes and "hides" unnecessary information.

Abstraction is an extension of encapsulation, but what's the difference?

  • Encapsulation - means hiding data like using getter and setter etc.
  • Abstraction - means hiding implementation using abstract class and interfaces etc.

But now I'm even more confused, what are abstract classes and interfaces?

Abstract Class

An abstract class is a simply a normal class that has some special exceptions:

  • An abstract class may have methods that do not have a body
  • An abstract class has to be sub-classed, at some level, to a non-abstract class before you can instantiate an object
  • It is not allowed to directly instantiate an object of an abstract class

So, why would I ever use such classes?

Well, they allow us to do multiples things:

  1. Consolidate common behavior (unlike an interface which only defines the contract)
  2. Provide default (and optionally override-able) implementations for functions

Let's look at a simple example:



//abstract parent class
abstract class Animal{
   //abstract method
   public abstract void sound();
}
//Dog class extends Animal class
public class Dog extends Animal{

   public void sound(){
    System.out.println("Woof");
   }
   public static void main(String args[]){
    Animal obj = new Dog();
    obj.sound();
   }
}


Enter fullscreen mode Exit fullscreen mode

Abstract class vs Concrete class

  1. An abstract class is useless until it is extended by another class.
  2. If you declare an abstract method in a class then you must declare the class abstract as well. You can’t have an abstract method in a concrete class. Its vice versa is not always true: If a class is not having any abstract method then also it can be marked as abstract.
  3. It can have non-abstract method (concrete) as well.

Interfaces

Alt Text

An interface is an abstract type that is used to specify a behavior that classes must implement.

Think of interfaces as a contract.

You have a bunch of rules which you must follow through but the details don't really matter.

For example, we have a contract for the behavior of a dog called DogInterface it will look something like this:



public interface DogInterface {
    public void bark();
    public void wiggleTail();
    public void eat();
}


Enter fullscreen mode Exit fullscreen mode

Here we are saying that every class that implements the DogInterface must have these three methods. As you can see there is absolutely no implementation details, it doesn't say how should a dog bark, wiggle its tail or eat. Having said that, we now have the ability to create different dog classes that all follow the same contract.



public class LabradorRetriever implements DogInterface {

    public void bark() {
        System.out.println("Woof, woof!!");    
    }

    public void wiggleTail() {
        System.out.println("wiggles tail");
    }

    public void eat() {
        System.out.println("eats food");
    }
}


Enter fullscreen mode Exit fullscreen mode

You might ask "Why would I ever want to use an interface?"

Interfaces in a nutshell guarantee that a class will have x methods.

This may sound too simple, but it actually is just that.

Nonetheless this small feature helps us tremendously, imagine we have a shipping service program and our client code uses the Car class to transport stuff. After some time our program gets popular and we know need to support planes, trains, ships, trucks, etc...

One way to do this is to create a common interface called TransportInterface that will be used by all the transport vehicles (airplane, car, etc...). This way our client code will not have to worry if the class Airplane will not have some common method.

Which to use? Abstract Classes or Interfaces?

As always it depends.

There are many different factors to consider.

But in general, an abstract class is used when you want a functionality to be implemented or override in subclasses. On the other hand, an interface will only allow you to describe functionality but no implementation. Also in most programming languages, a class can only extend one abstract class, but it can take advantage of multiple interfaces.

Coming back to abstraction

This post definitely took a turn, but it was necessary to talk about abstract classes and interfaces.

In a nutshell:

Abstraction is an extension of encapsulation where it literally hides implementation using either abstract classes or interfaces.

Inheritance

Alt Text

Inheritance is the mechanism of basing an object or class upon another object or class, retaining similar implementation.

A common problem in programming is that objects are too damn similar.

Objects are often very similar, have common functionality but they are not entirely the same.

Now comes the dilemma that every programmer goes through.

"Do I create an entirely new class or put all common functionality in a base class?"

I'm not gonna say which option is better, but we are talking about OOP today. That means we are gonna pick the second option, creating a base class that will store all common functionality.

School Example

Imagine we were tasked to create a school management system and we have two entities called Student and Teacher. In our first version of the app we implemented it them like this:



public class Student {
    private String name;
    private String last_name;
    private String gender;
    private String classroom;
    private String year;

    public void attendClass(){
        System.out.println("Attend Class");
    }

    public void eatSandwich(){
        System.out.println("Eating a sandwich");
    }
}


Enter fullscreen mode Exit fullscreen mode


public class Teacher {
    private String name;
    private String last_name;
    private String gender;
    private String schedule;
    private String subject;

    public void teachClass(){
        System.out.println("Teaching a class");
    }

    public void eatSandwich(){
        System.out.println("Eating a sandwich");
    }
}


Enter fullscreen mode Exit fullscreen mode

As you can see there are many common states and behaviors, how about we extract all that to a common class called Human



public class Human {
    protected String name;
    protected String last_name;
    protected String gender;

    public void eatSandwich(){
        System.out.println("Eating a sandwich");
    }
}


Enter fullscreen mode Exit fullscreen mode

PS. I set all my variables protected for them to be accessible in subclasses.

With this we can inherit all common states and behaviors into our Student and Teacher class.



public class Student extends Human {
    private String classroom;
    private String year;

    public void attendClass(){
        System.out.println("Attend Class");
    }
}


Enter fullscreen mode Exit fullscreen mode


public class Teacher extends Human {
    private String schedule;
    private String subject;

    public void teachClass(){
        System.out.println("Teaching a class");
    }
}


Enter fullscreen mode Exit fullscreen mode

Congratulations we have removed duplicated code, and that is a good sign.

Coming back to inheritance

Inheritance isn't that simple, there are actually different types of inheritance.

  1. Single Inheritance: This is the simplest kind of inheritance where we inherit from a parent class. Just like our example above with teachers and students.
  2. Multi-Level Inheritance: An inheritance becomes multi-level when it inherits from a subclass. For example, let's imagine from our example above that we added a class called Intern. Intern has the same state and behavior as Teacher but with some extra fields, so we simply inherit from Teacher. This is multiple inheritances because now class Intern inherits from both Teacher and Human.
  3. Multiple Inheritance: Happens when a class inherits more than one parent class. This is usually not allowed in most programming languages but is available in some.
  4. Hierarchical inheritance: Is when multiple child classes inherit from the same parent class. For example we have a class Dog and Cat that both inherit from class Animal.
  5. Hybrid Inheritance: When there is a combination of more than one form of inheritance, it is known as hybrid inheritance.

Benefits of Inheritance

  1. Code reusability
  2. One superclass can be used for the number of subclasses in a hierarchy.
  3. No changes to be done in all base classes, just do changes in parent class only.
  4. Inheritance avoids duplicity and data redundancy.
  5. Inheritance is used to avoid space complexity and time complexity.

Precaution

Now I am not saying to always extend your classes, doing that will make your code very coupled together. Another approach would be to use composition or aggregation.

You can read more about it here

Polymorphism

Alt Text

Polymorphism is the ability of an object to take on many forms.

Let us break down the word:

  • Poly = many: polygon = many-sided, polystyrene = many styrenes , polyglot = many languages, and so on.
  • Morph = change or form, morphology = study of biological form, Morpheus = the Greek god of dreams able to take any form.

So polymorphism is the ability (in programming) to present the same interface for differing underlying forms (data types).

The classic example is the Shape class and all the classes that can inherit from it (square, circle, dodecahedron, irregular polygon, splat and so on).

With polymorphism, each of these classes will have different underlying data. A point shape needs only two co-ordinates (assuming it's in a two-dimensional space of course). A circle needs a center and radius. A square or rectangle needs two coordinates for the top left and bottom right corners and (possibly) a rotation. An irregular polygon needs a series of lines.

By making the class responsible for its code as well as its data, you can achieve polymorphism. In this example, every class would have its own Draw() function and the client code could simply do:



shape.Draw()


Enter fullscreen mode Exit fullscreen mode

to get the correct behavior for any shape. This is in contrast to the old way of doing things in which the code was separate from the data, and you would have had functions such as drawSquare() and drawCircle().

Types of Polymorphism

Usually in interviews they ask questions like:

"What is polymorphism?"

You answer them properly, then to throw you off your game they ask:

"What are the different types of polymorphism?"

Now you have two options:

  1. Answer the question cause your smart.
  2. Make up some stuff.

Unfortunately, I had this same question asked me, and I failed to answer. This is why we will talk about the types of polymorphism.

The two types of polymorphism are dynamic polymorphism and static polymorphism.

Dynamic Polymorphism

This is also known as:

  • Run-Time polymorphism
  • Dynamic binding
  • Run-Time binding
  • Late binding
  • Method overriding

This is your standard polymorphism. It's basically when a subclass has a method with the same name and parameters of a method in a parent class, these methods are in different forms (this is known as method overriding).

For example, let us illustrate our shapes example above.



public class Shape {
    protected int width;
    protected int height;

    // some more functionality for shape

    public void draw(){
        // draws a shape using the width and height.
    }
}


Enter fullscreen mode Exit fullscreen mode


public class Circle extends Shape {
    private int radius;

    @Override
    public void draw() {
        // draw a circle code
    }
}


Enter fullscreen mode Exit fullscreen mode


public class Square extends Shape {

    @Override
    public void draw() {
        // specifically draw a square
    }
}


Enter fullscreen mode Exit fullscreen mode

Our client code will look something like this:



public static void main(String[] args) {
        Shape shape = new Shape();
        Shape circle = new Circle();
        Shape square = new Square();

        shape.draw(); // calls the draw method in shape class
        circle.draw(); // calls the draw method in circle class
        square.draw(); // calls the draw method in square class
    }


Enter fullscreen mode Exit fullscreen mode

As you can see, both our Circle and Square class inherit from Shape class. They also override the draw() method in Shape class.

Static Polymorphism

This is also known as:

  1. Compile-Time polymorphism
  2. Static binding
  3. Compile-Time binding
  4. Early binding
  5. Method overloading

This is basically when a method has many forms in the same class.

Let's look at an example:



public class Calculator {
void add(int a, int b) {
System.out.println(a+b);
}
void add(int a, int b, int c) {
System.out.println(a+b+c);
}
}

Enter fullscreen mode Exit fullscreen mode


public static void main(String args[]) {
Calculator calculator = new Calculator();

    <span class="c1">// method with two parameters gets called</span>
    <span class="n">calculator</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="mi">10</span><span class="o">,</span> <span class="mi">20</span><span class="o">);</span> <span class="c1">// output: 30</span>

    <span class="c1">// method with three parameters get called</span>
    <span class="n">calculator</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="mi">10</span><span class="o">,</span> <span class="mi">20</span><span class="o">,</span> <span class="mi">30</span><span class="o">);</span> <span class="c1">//output: 60</span>
<span class="o">}</span>
Enter fullscreen mode Exit fullscreen mode
Enter fullscreen mode Exit fullscreen mode




Benefits of Polymorphism

  • It helps the programmer to reuse the codes, i.e., classes once written, tested and implemented can be reused as required. Saves a lot of time.
  • Single variable can be used to store multiple data types.
  • Easy to debug the codes.

Conclusion

The four principles of object-orientated programming are:

  1. Encapsulation: means hiding data like using getter and setter
  2. Abstraction: hides implementation using interfaces and abstract classes.
  3. Inheritance: mechanism of basing an object or class upon another object or class, retaining similar implementation.
  4. Polymorphism: ability of an object to take on many forms.

Congratulations, now you can answer one of the most asked questions in interviews and kick ass.

If you got any questions, then feel free to leave them down in the comments section below.

💖 💪 🙅 🚩
tamerlang
Tamerlan Gudabayev

Posted on March 21, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

OOP Principles For Dummies
computerscience OOP Principles For Dummies

March 21, 2021