The Four Principles of Object-Oriented Programming

Updated Friday, 08 December 2023 by Ryan Kueter
Object-Oriented Programming (OOP) provides a number of benefits that are commonly known as the “Four Principles of Object-Oriented Programming.” This article explores these four principles and how they apply to real-world code. This article uses C# in the examples. However, these principles apply to other OOP languages as well.

Abstraction

Abstraction simply means hiding implementation details. And that may be accomplished within the object or by using interfaces. Typically, an object exposes a limited number of properties or methods for the programmer to use and abstracts away other implementation details. For example, when retrieving the “age” of the person class, it may perform a quick calculation based on the person’s birthdate and the current date. The developer doesn’t have to worry about that calculation. All the developer has to do is call the age property. That’s because those implementation details are abstracted away in the class.

Interfaces also provide abstraction and are used for many things. But a couple of common uses are to make classes or libraries more interchangeable or to address cross cutting concerns. For example, in my development environment, my program may use a library that writes files to my local computer. But if that application is deployed to the cloud, it may use a different library that writes those files to cloud storage. Because both libraries use the same interface, and the application code works with those libraries by using the interface, they may be swapped out without the application knowing. 

Encapsulation

Encapsulation is what enables an object to expose or hide object members, often by using accessors. When exposing object members, such as name, age, and height of the person, those properties could be “public” or “internal” in some languages. However, when making a member hidden, it could be made “private.” And if a property should not be modified, it could be made “read-only.” Read-only properties are only written to during initialization. This prevents developers from accessing implementation details they should not be accessing. And it makes the classes easier to work with.

public class Person
{
    public string? FirstName { get; init; }
    public string? LastName { get; init; }
    public DateTime Birthdate { get; init; }

    public Person(string firstName, string lastName, DateTime birthDate) =>
    (FirstName, LastName, Birthdate) = (firstName, lastName, birthDate);

    public int GetAge() => DateTime.UtcNow.Year - Birthdate.Year;
}

Inheritance

Inheritance is the ability of an object to inherit the members of another object or interface. Inheritance is useful in scenarios where the functionality of an existing data type could be reused or extended. If an object inherits another object or interface, it acquires the members that are inheritable. An example would be an abstract base class that contains functionality used by a number of different classes. In that instance, those classes may simply inherit that base class and be able to use that functionality. 

Class may also be prevented from being inherited as a result of being sealed in circumstances where the developer may not want that class to be inherited.

public sealed class Person
{
    public string? FirstName;
    public string? LastName;

    public string GetSignature()
    {
        return $"{FirstName} {LastName}";
    }
}

Polymorphism

Polymorphism, which means “many forms,” is the ability to change the functionality of an inherited object. For example, a C# class may have a “virtual” method. And that method may be overridden, using the “override” keyword, to allow developers to include their own custom functionality.

public class Person
{
    public string? FirstName;
    public string? LastName;

    public virtual string GetSignature()
    {
        return $"{FirstName} {LastName}";
    }
}

public class Programmer : Person
{
    public string? Title;
    public override string GetSignature()
    {
        return $"{FirstName} {LastName}, {Title}";
    }
}

In C#, virtual inheritance may be stopped by sealing the override. 

public class Programmer : Person
{
    public string? Title;
    public sealed override string GetSignature()
    {
        return $"{FirstName} {LastName}, {Title}";
    }
}