Object-Oriented Programming Fundamentals are key to all modern Software Developer. In this article, you will learn all the basics and some complex topics about them. If you prefer a more visual format here is a short video that covers all the topics:
Let's start with the definitions of the basic constructs of the paradigm: Object, Message, and Methods.
An object is an entity, a representation of a concept. We create a model using objects and their interactions. They don´t necessarily have to be real objects, they can be conceptual. For example, if I owe money to someone that’s a debt, and it can be an object in our model even if it isn’t a tangible object in the real world.
The way objects interact between themselves is through messages. To send a message to an object first I need to know it. That will be done through references but we will touch base with that topic later on. Then, I need to know which messages the object understands, what can it do, I don´t care how it does it, but what it is capable of doing. For example, I know my cat can eat, play with cables, and purr, If I were to build a model of my cat those would be the messages the object would understand.
Then the object has definitions for every message it can receive, that is a method. You can think of it as a function or procedure if you are familiar with other paradigms. Basically, it is which actions to take to resolve the message received.
Let’s talk about how we know objects and how to handle state.
A reference is the way we know and access an object. It is basically a memory address that points to said object if we want to go low-level. Once you have a reference to an object you can send messages to it.
The state of an object is composed of all the attributes it has. This state can change over time or be constant. For example, if we have an object CoffeeCup its state could be its color, it’s capacity, and whether it is filled with coffee or not. Clearly its color and capacity won´t change over time, but whether or not it is filled with our delicious coffee will.
An object has properties as a way to let others access its state. Properties offer a get and a set method to retrieve a value or set it. It is the responsibility of the object to determine how it will offer these properties as an interface to its state to ensure correct and expected behavior. Following the previous example for our coffeeCup we would have a get property to show our beautiful color and to let the consumer know our capacity but we won´t allow them to set these values. Unlike filledWithCoffee which will offer a get and a set method to allow the consumer to change this value unless we want to tie this change of state to other actions, but that is a topic for another video!
The first fundamental pillar of Object-oriented programming is Encapsulation, so let’s talk about it. Encapsulation is the principle of making every object owner and responsible for its own state. Basically, we shouldn’t expose our state and allow others to modify it as they want. Instead, what this principle reinforces is to really think hard and come up with the minimum number of messages that our object has to understand and expose to the consumers. Of course, with those messages our object has to be able to maintain its own state and be useful, otherwise, this does not make any sense. There is no point in using Object-oriented programming and then making all our attributes public and allow consumers to change all our state without any validation or restriction.
Our next topic is scope. The scope is basically the reach level a variable or a property has. If you are inside of a method in your object all the variables you create In there can only be used inside of the said method. If you instead define a variable or attribute at the object level then it will be usable from all the methods of your object. Another branch of scope is for your property accessors, you can define from where can be accessed your properties in most languages. Some options here are private, public, and protected. Keep in mind you can control who can access those properties to help you out with the encapsulation of your object.
Lastly, we want to talk about interfaces. The interface of an object is the set of all the messages it can understand. This is very important and very powerful because we will later learn about the benefits of having different objects having the same interface and how that allows us to design and develop better solutions. It is worth mentioning that in typed languages like C#, Java, or typescript an Interface is an even stronger concept since it obliges to implement methods definitions for all the messages described in an interface, it is more like a contract.
Now its finally time to talk about how to create our precious objects.
Classes are one of the most important concepts and construct of object-oriented programming. The idea is simple, a class is a blueprint for creating objects. In a class we will define all the properties we want our objects to have (its state) and all the messages it will understand with its corresponding implementation (methods). For example, I have 3 cats in my house. If I want to model this in an Object-oriented program, I would write a class Cat and then create 3 instances of the said class to have 3 objects, one for each cat. The class Cat would have properties like the age and the color and methods like eat, sleep, and purr. Then I would be able to interact with all my beautiful cats through those messages!
The next big topic is Constructor. A constructor is a unique and special method that every class has to define, that’s because the constructor has the definition of how an object of its class is created. In most languages, if you don’t provide a constructor your class would have one by default that doesn’t do anything specific for your class. Basically in this method, you would put any logic that is necessary for an object to be created and get a valid state. For example, if you remember our cute coffee cup, in the constructor of it we would ask for the color of the cup and its capacity.
This is because we cannot create a cup without knowing its color and capacity, it doesn’t make any sense, and we could also default the value of filledWithCoffee to false since we just created the cup. Later on, the consumer of the object would be able to get the color and capacity and get or modify the value of filledWithCoffee.
Inheritance is the second fundamental pillar of Object-oriented programming. The idea is to create class hierarchies based on the relationship of “is a”. For example: if we want to model payments, we could have a Check class and an Electronic Fund Transfer class, both would inherit from a payment class. Both a check and an EFT are payments, but they are different from one another and will probably have different states and behavior while also sharing some characteristics and an interface. We say that the class payment is a superclass and the ones that inherit from it are subclasses.
With this in mind, we have to start thinking about how are we going to handle context, because now when we are inside of a class I have access to properties and methods that are inside of my class but also in my superclass (and the superclass of the superclass and so on). The standard way to solve this is to have a keyword to reference its own context, that would be this or self in most languages, and another keyword to access things in the context of my superclass and that would be super or base.
Now, let's move to Method lookup. Now we have hierarchies and when an object receives a message it has to look for the definition of a method with a signature that matches this message, potentially, in all the hierarchy. The process of finding this definition is called method lookup and it is basically from the bottom up. We will start on the class of the instance that received the message and if there is no definition in this class it will go and search in its superclass and so on until it finds a definition or reaches the end of the hierarchy in which case it would produce an exception.
Something great about Object-oriented Programming is that it allows us to convey ideas through objects and class diagrams. By now you should be comfortable thinking about classes and objects, so lets put them on paper with a set of rules and standard drawings known as UML. UML is Unified Modeling Language and its purpose is to give us tools to share design and put ideas down to earth without having to code everything.
UML Standard Object diagrams can be somewhat easily confused with class diagrams that’s why I have found a pseudo standard that fits better. In this variation, an object will be drawn as a circle with a name and the attributes we want to have in it linked to other objects through references. A reference will be drawn as an arrow. With this, we can create object graphs to visualize relationships and a possible scenario with a given state for our system.
Then we have the class diagrams. For classes we will use rectangles, with the name on top, then a section for attributes, and lastly a section for methods. This can be as detailed or as abstract as the diagram needs. Usually, it is better to only put what is really necessary and leave details for later when we want to implement this. But on occasions, we might want to have a clear full interface for an important class. We will connect classes that have a reference to another class with an arrow filled. And we will draw relationships of inheritance with an arrowhead empty. This way we can create complex designs with hierarchies and references between classes in a visual and convenient way.
That will be all for this full article on Object-Oriented Programming Fundamentals! To get more of this content subscribe to my Youtube channel here.