The 4 Primary Object Oriented Principles Explained in Simple Terms

In this article, I will be explaining using simple coded examples the 4 primary OOP (Object Oriented Programming) concepts. These are Encapsulation, Abstraction, Inheritance and Polymorphism.

These terms are often coded everyday by experienced developers, but if you asked them what these terms mean it's likely they couldn't tell you. This is no bad thing, developers are expert coders, not university lecturers. However, the definitions will be a useful reminder for experienced developers and will come in very handy if your attending interviews as these questions crop up a lot.

For each principle, I will be explaining it in three ways providing an Academic, Laymans terms and Interview definition.

The Academic definition is the most complex and hard to understand. Used by universities and by Computer Science lecturers who are far more skilled at as I call it "talk the talk" (can expertly describe programming principles) but not "walk the walk" (confidently write code).

The Layman's terms will be the most useful and easiest to understand. This is a definition in its most simple of terms.

The interview definition will be good if you are asked what these principles mean and how they are used in developing OOP during an interview. It provides not only an explanation but a real coded example so you can gain a deep understanding.


Encapsulation

Encapsulation is the easiest of the 4 to understand, it’s essentially just “hiding code”. Hiding implementation code and logic that is only used for a class that has public methods and can be invoked by others areas of the application. A system only needs to be able to see methods that are public, but if a public method has detailed logic, this needs to be set as private so the system cannot invoke it.

  1. Academic - A language mechanism for restricting direct access to some of the objects components.
  2. Laymans – if a method within your class is used only by your class, set it as private.
  3. Interview – Let's say you have a class that has logic that is used only by its class, Refactor that logic into a private method to “encapsulate” the code so it's not exposed to other references where it's not necessary. This is best practice to ensure IDE Intellisense is more refined for methods, properties and fields that are exposed.

Encapsulation Coded Example

[TestClass]
public class CodedExample_Encapsulation
{
	[TestMethod]
	public void TestEncapsulation()
	{
		Car MyCar = new Car();

		// whats the Fuel level?
		int FuelLevel = MyCar.GetFuelLevel;
	}
}

public class Car
{
	public int GetFuelLevel
	{
		get
		{
			return CalculateRemainingFuelLevel();
		}
	}

	private int CalculateRemainingFuelLevel()
	{
		int FuelLevel = 0;

		// **************
		// complex logic to calculate the fuel level
		// **************

		// **************
		// even more complex logic....
		// **************

		return FuelLevel;
	}
}


Abstraction

The concept of abstraction is working with an API or endpoint (public methods) that we know how to invoke and what is returned, but we don’t care about the inner workings of how it actually works. An example of this would be in relation to a Car object. When we press the on button or turn the key, the engine starts. As the driver we don’t care how the engine actually works all we have is an "interface" where we can start and stop the engine, a steering wheel that can steer the car and a gear stick where we can change gear. These could be thought of as an Interface. I wrote an article about interfaces using USB as an example – you can view it here ->  https://www.intermittentbug.com/article/articlepage/understanding-interfaces-in-c-sharp/2018

  1. Academic - The essence of abstractions is preserving information that is relevant in a given context, and forgetting information that is irrelevant in that context.
  2. Laymans – Abstraction simply means we don’t need to understand the actual code within in a DLL we are referencing, we just need to understand what data type it returns and any parameters it requires in order to invoke its functionality.
  3. Interview – If I am writing a class library, the depending application does not need to understand the inner workings, it only needs access to the method endpoints or APIs. I can use an Interface so any object that inherits the interface knows exactly what the options are for invoking it.

 Abstraction coded Example

[TestClass]
public class CodedExample_Interface
{
	[TestMethod]
	public void TestMethod1()
	{
		// create a Car Object
		IVehicle car = new Car("Lexus", "GS450h");
		Assert.IsTrue(car.NumberOfWheels == 4);

		// create a Motorbike Object
		IVehicle motorbike = new Motorbike("Honda", "Goldwing");
		Assert.IsTrue(car.NumberOfWheels == 2);
	}
}

public class Car : IVehicle
{
	private string _make;
	private string _model;

	public int NumberOfWheels
	{
		get
		{
			return 4;
		}
	}

	public string Make
	{
		get
		{
			return _make;
		}             
	}

	public string Model
	{
		get
		{
			return _model;
		}
	}

	// Car Constructor
	public Car(string Make, string Model)
	{
		_make = Make;
		_model = Model;
	}

	public bool EngineStart(Guid Key)
	{
		bool Started = false;

		// *********************
		// EngineStart logic here
		// *********************

		return Started;
	}

	public int FuelLevel()
	{
		int CurrentFuelLevel = 0;

		// *********************
		// EngineStart logic here
		// *********************

		return CurrentFuelLevel;
	}

	public int Speed()
	{
		int CurrentSpeed = 0;

		// *********************
		// EngineStart logic here
		// *********************

		return CurrentSpeed;
	}
}

public class Motorbike : IVehicle
{
	private string _make;
	private string _model;

	public int NumberOfWheels
	{
		get
		{
			return 2;
		}            
	}

	public string Make
	{
		get
		{
			return _make;
		}
	}

	public string Model
	{
		get
		{
			return _model;
		}
	}

	// Motorbike Constructor
	public Motorbike(string Make, string Model)
	{
		_make = Make;
		_model = Model;
	}

	public bool EngineStart(Guid Key)
	{
		bool Started = false;

		// *********************
		// EngineStart logic here
		// *********************

		return Started;
	}

	public int FuelLevel()
	{
		int CurrentFuelLevel = 0;

		// *********************
		// EngineStart logic here
		// *********************

		return CurrentFuelLevel;
	}

	public int Speed()
	{
		int CurrentSpeed = 0;

		// *********************
		// EngineStart logic here
		// *********************

		return CurrentSpeed;
	}
}

public interface IVehicle
{
	// properties
	string Make { get; }
	string Model { get; }

	int NumberOfWheels { get; }

	// Metods
	bool EngineStart(Guid Key);
	int FuelLevel();
	int Speed();
}


Inheritance

When using inheritance we can inherit from a base class to reuse its fields, properties, methods and constructors. This is useful for achieving code reuse. A base class can be thought of as a parent class and an inheriting class would be a child class. The classic example is having a class "Dog" which inherits from the base class "Animal". The coded example I will be using will be Car related and show you how to use inheritance for using constructors and implementing base classes.

  1. Academic - Inheritance (OOP) is when an object or class is based on another object (prototypal inheritance) or class (class-based inheritance), using the same implementation (inheriting from an object or class) specifying implementation to maintain the same behavior (realizing an interface; inheriting behavior).
  2. Laymans – Inheritance is simply using the functionality of other classes. The most typical example is inheriting from a base class. This base class likely contains methods and properties that can be inherited by multiple classes. This ensures code reuse.
  3. Interview - when creating classes that have functionality that can be shared by other classes, its best practice to refactor the shared methods into a base class. I can further enhance my base class by adding methods that are set as virtual so inheriting classes can override their functionality and keep the same method name. Base class constructors can also be called in conjunction with child class constructors.

 Inheritance coded Example

[TestClass]
public class CodedExample_AbstractClass
{
	[TestMethod]
	public void TestMethod_Car()
	{
		// create a Car Object
		Car car = new Car("Lexus", "GS450h", "Automatic", new Guid());
		Assert.IsTrue(car.Make == "Lexus");
		Assert.IsTrue(car.Model == "GS450h");
		Assert.IsTrue(car.NumberOfWheels == 4);
		Assert.IsTrue(car.GetTransmissionType == "Automatic");
	}

	[TestMethod]
	public void TestMethod_Motorbike()
	{
		// create a Motorbike Object
		Motorbike motorbike = new Motorbike("Honda", "Goldwing", "Petrol", new Guid());
		Assert.IsTrue(motorbike.Make == "Honda");
		Assert.IsTrue(motorbike.Model == "Goldwing");
		Assert.IsTrue(motorbike.NumberOfWheels == 2);
	}
}

public class Car : Vehicle
{
	public int NumberOfWheels
	{
		get
		{
			return 4;
		}
	}

	private string _TransmissionType;
	public string GetTransmissionType
	{
		get
		{
			return _TransmissionType;
		}
	}

	// Car Constructor
	public Car(string Make, string Model, string Transmission, Guid VehicleKeyGuid) : base(Make, Model, VehicleKeyGuid)
	{
		_TransmissionType = Transmission;
	}
}

public class Motorbike : Vehicle
{    
	public int NumberOfWheels
	{
		get
		{
			return 2;
		}            
	}

	private string _FuelType;
	public string GetFuelType
	{
		get
		{
			return _FuelType;
		}          
	}        

	// Motorbike Constructor
	public Motorbike(string Make, string Model, string FuelType, Guid VehicleKeyGuid) : base(Make, Model, VehicleKeyGuid)
	{
		_FuelType = FuelType;
	}
}

// this is the base class "Vehicle"
public class Vehicle
{
	protected string _make;
	protected string _model;
	protected Guid _vehicleKeyGuid;

	public string Make
	{
		get
		{
			return _make;
		}
	}

	public string Model
	{
		get
		{
			return _model;
		}
	}

	protected Vehicle(string Make, string Model, Guid VehicleKeyGuid)
	{
		_make = Make;
		_model = Model;
		_vehicleKeyGuid = VehicleKeyGuid;
	}

	protected bool EngineStart(Guid Key)
	{
		bool HasStarted = false;

		// *********************
		// logic here..
		// *********************

		return HasStarted;
	}

	protected int FuelLevel()
	{
		int CurrentFuelLevel = 0;

		// *********************
		// logic here..
		// *********************

		return CurrentFuelLevel;
	}

	protected int Speed()
	{
		int CurrentSpeed = 0;

		// *********************
		// logic here..
		// *********************

		return CurrentSpeed;
	}
}

 

Polymorphism

Polymorphism out of the 4 is the most tricky to understand. The term "polymorphism" essentially means change and is mostly related to overriding existing functionality into new functionality using the override keyword to override existing functionality in base classes. I will demo this in the code below. 

  1. Academic -In object-oriented programming, polymorphism refers to a programming language's ability to process objects differently depending on their data type or class. More specifically, it is the ability to redefine methods for derived classes.
  2. Laymans – Polymorphism is related to the ability to override method functionality of a base class marked as override.
  3. Interview - the ToString() method is a good example to use when asked about polymorphism during an interview. Let's say we have a car class and a vehicle base class. In the vehicle class is a ToString() method marked as override that will return the name of the vehicle using (make + " " + model). In the Car class that is the inheriting class of Vehicle we could have a ToString() method that is marked as override which return the make, model and transmission. This is known in OOP as Polymorphism and explained in the coded example below.

 Polymorphism coded Example

[TestClass]
public class CodedExample_Polymorphism
{
	[TestMethod]
	public void TestMethod_Polymorphism_Car()
	{
		// create a Car Object
		Car car = new Car("Lexus", "GS450h", "Automatic");

		Assert.IsTrue(car.Make == "Lexus");
		Assert.IsTrue(car.Model == "GS450h");
		Assert.IsTrue(car.ToString() == "Lexus GS450h Automatic");
	}

	[TestMethod]
	public void TestMethod_Polymorphism_Vehicle()
	{
		// create a vehicel object
		Vehicle vehicle = new Vehicle("Lexus", "IS300H");

		Assert.IsTrue(vehicle.Make == "Lexus");
		Assert.IsTrue(vehicle.Model == "IS300H");
		Assert.IsTrue(vehicle.ToString() == "Lexus IS300H");
	}
}

public class Car : Vehicle
{
	// Car Constructor
	private string _transmission;

	public Car(string Make, string Model, string Transmission) : base(Make, Model)
	{
		_transmission = Transmission;
	}

	public override string ToString()
	{
		return $"{base.Make} {base.Model} {_transmission}";
	}
}

// this is the base class "Vehicle"
public class Vehicle
{
	protected string _make;
	protected string _model;
	protected Guid _vehicleKeyGuid;

	public string Make
	{
		get
		{
			return _make;
		}
	}

	public string Model
	{
		get
		{
			return _model;
		}
	}

	public Vehicle(string Make, string Model)
	{
		_make = Make;
		_model = Model;
	}

	public override string ToString()
	{
		return $"{Make} {Model}";
	}
}

 

So, there we have it, each of the principles explained in simple terms that are easy to understand and relate to everyday development. If you are looking for a job in IT that uses OOP programming languages such as C#, Java, PHP, ect, ect interviewers normally quiz candidates understanding of the principles so it’s well worth revising the interview definitions in preparation.


JGilmartin Profile Image

JGilmartin

Technical Architect at Pinewood Technologies

Rating: 2890

C# Expert

Offline


Tutorial Statistics
  • Views: 874
  • Comments: 0
  • Author: JGilmartin (2890)
  • Date: 14/5/2017 17:32
Tags
OOP

© 2016 - 2018 - IntermittentBug