Object Oriented Programming Concepts With a Systematic Approach to Write Better Code

Haaaah another article on object oriented programming. You might be thinking that I will be discussing same OOP definitions with boring examples. The same definitions and examples that you have studied before. Maybe in your class or when preparing for a job interview. But today I will not rephrase those disjointed definitions but give you a simple layout that will make it easy for you to understand OOP concepts.

OOP is easy to understand if you understand it with the metaphors like Cat, Duck, Animal and other similar metaphors but sometimes it is hard to swallow these metaphors. How can a child have the skills of his father? There can be some similarities because of DNA but will you go for an annual checkup to a child whose father is a doctor?

Most of the OOP material is filled with these kinds of metaphors. There is nothing wrong with these metaphors and examples if you introduce OOP concepts to a beginner programmer. But available literature is only filled with these kinds of examples. They never progress in the quality of OOP examples. They introduce with metaphors and end at metaphors.

Well, I also have struggled with OOP concepts during my undergrad studies. I understand OOP concepts but when faced with writing actual code I became stall and could not think where to start. At one time I thought that I should stop learning OOP but the world around me kept telling me the importance of OOP.

If you combine all embedded developers and low-level API developers then that will only make 10% of all the developers in the universe. The remaining 90% developers are programming in OOP based programming languages.

object oriented programming

Besides, Object-oriented programming skills will be with you for life. On the contrary, if you are tied to a specific framework for two, three or even five years then my friend you are in the rabbit hole. What happens if that framework is replaced by another optimized framework– You will have to start from zero.

But if you know object-oriented concepts and have applied them firmly in your work then you have that experience for the lifetime. You can always get leverage out of that object-oriented programming experience.

Also, I don’t want to be a kind of developers who write only glue code and become just an API consumer. I want to learn skills that I can use to produce frameworks that are used by others.

So how I grasp the OOP concepts. It is simple. Different mindset. Over the past 10 years of programming experience, I have developed a mindset towards OOP and I will present that mindset in the following template or layout. This is a systematic approach that I will use if I introduce OOP concepts to a new student.

  1. Context: Previously people were tired of procedural programming because the information was available to all
  2. So, they develop a method to hide information called encapsulation
  3. They need to communicate besides hiding so they invented communication methods: association and inheritance
  4. Communication came along with dependency problem. The solution is: abstraction and polymorphism
  5. Design patterns are invented to lower the dependency issues. For design patterns, I have another article here.

 

Context of OOP: Information is Everywhere

Well after reading the Steve Jobs biography I understand the evolution of computers, operating systems, and graphical user interface. All of this helped me understand modern technologies. Therefore it is necessary to understand a little bit of background.

Where is this ‘OOP’ fits in the larger context of software development? Is it a process? Is it an architecture or something else? Well, I am feeling stupid right now by asking these question but there are people who ask these type of questions and they are still confused. Object-oriented programming is a development methodology. 

Developers, especially young developers know only about the OOP as a development methodology. If they read a little bit of history then they will know that there is another development methodology that people have abandoned or tried to abandon and that is procedural development methodology. Procedural programming languages like COBOL, Fortran, and Pascal were the default choices for our programming ancestors and before that assembly language programming was a must for every computer scientist.

In procedural programming, we divide a large set of instructions into procedures. Like functions in C#. Before procedural programming, there was another paradigm and that is monolithic programming. In monolithic programming, everything is written in one large method and all the variables are defined at the topmost location. But as program size grows managing monolithic and procedural code became difficult so OOP was invented.

Enough context and let’s stick to our layout. But before deep diving let me introduce you to the Class and Objects.

A common question that people always ask is: “how we come up with classes for our code”.

Class and How to Come up With New Classes

Imagine you have opened up your favorite editor and have started a new project or working on new requirements or converting your good old procedural code to object-oriented code. How would you start?

First, you will have to come up with classes that you will use. The biggest challenge for developers is that they could not come up a good set of classes or don’t know how to start writing code in OOP and they end up in writing a giant single class that has 100 variables and a million methods.

So, what is a class then? A class is a ‘blueprint’ to define your idea. A class can represent a physical object like chair, screen, humans, and animals. A class can represent a role such as a student and an employee. A class can also represent an abstract concept. For example, mathematical concepts: Circle, Kalman filter, and others.

A class has a name, attributes, and behavior. Attributes or data can be of any primitive data type. The class name should represent a concept in the domain you are working on. Following are some examples where I come up with some classes for the given user requirements.

Example 1: What classes can be there if you intended to develop a manufacturing factory processing system?

Here is the class diagram that I come up initially:

class diagram

 

Analyze this design. Do you think that Employee class should be part of this set of classes? ‘Employee’ is not a bad class name but it is a bit out of context. Because we are modeling the Process and employee should not be the part of it.

Example 2: Come up with classes that can measure the shock applied to a car using shock sensors.

Here is the initial model that I come up:

Class Diagram

Now, look at the class ‘Measure’. It is a verb and cannot be the name of the class. It can be a function of a class. A class name should be a noun.

The idea in my mind is that a suspension system should acquire the data from shock sensor and apply the model to sensors values. But ‘Measure’ is not a good class name. Instead of that, I should use ‘DataAcquisition’ as a class name. I have compiled tips for coming up with new classes in PDF. Download the PDF.

How to come up with New Classes

I also have another real-world example of applying object-oriented principles using a systematic approach. Get the report here.

Encapsulation: Hiding the information

Let me share a personal story. One night there was a call from my boss. I have to update the demo for our product and show a couple of parameter on the screen. Demos in trade shows are important for marketing. Usually, it is a high-pressure situation. Every engineer was counting on me.

The update was small. I have to add two text fields to the display. I create a class and since both fields were related therefore I put them in a single class and use the object of that class. I did this to make the code clean. Because in such stressed situations you cannot afford to make mistakes. The update worked flawlessly.

One of the engineers praises me in such a way that I still remember him after so many years. He told me that “Wow you created a new variable!”. He was not a software engineer so we can forgive him.

First of all, I don’t want my readers to be like that i.e treating an object like a variable. Secondly, you can see that how I used encapsulation to save the day. You merge one or more data and/or one or more method into a single entity and that is called encapsulation. This is what I do with the demo code I encapsulated two related data.

Encapsulation is also defined as the mechanism for data hiding/data protection/data security. Data hiding is achieved via access modifier. If a data member is defined using ‘private’  access modifier it will be accessible within the boundary of the class and if an access modifier is public it will be accessible by everybody else. But this definition needs clarification. Let’s see if it is true for the following example:

Example 1:

class StoreItem

{

  private int itemPrice;

  public int GetPrice()

  {

    return itemPrice;

  }

 public void SetPrice(int price)

 {

  itemPrice=price;

 }

}

Here I define a private data member and give it’s access to everybody else via a public method. Is the item price hidden? Let’s see another example:

Example 2:

class StoreItem

{

  public int itemPrice;

}

Everybody can access the item price since it is public now. So what is the difference in the above two code examples? This is not data hiding and if someone told you that the first example is data hiding then you should run away.

In my opinion, data hiding is controlled access to internal data via public methods. You are hiding data if the outside user does not know how many variables are in your class but still get the desired result from your class via public methods.

Example 3:

class Process
{
private int ingredient1;
private int ingredient2;
private int ingredientFromOutside1;
private int ingredientFromOutside2;

public int GetFinalProduct(){

 int result = GetLocalProduct()+GetProductFromOutside();
 return result;

}
private int GetLocalProduct()
{
  return ingredient1+ingredient2;
}
private int GetProductFromOutside()
{
  return ingrdientFromOuside1+ingredientFromOutside2;
}


}

In example 3, there are several variables and I hid them from the outside world and give only the controlled access to them. Outside the class, no one knows how many data members or methods are there. They just know one public method named GetFinalPoduct and nothing else. In this way, we hide data from outside world using encapsulation.

Accessors

In example 1, I have just exposed the instance variable and it is called the property type. There are several methods to access property type:

1) Write your own public methods for accessing member variables (first example)

2) Make your member variables public (second example–never use that)

3) Use accessors

Writing your own methods is a good approach but it is not extensible. The most suitable method is using accessors. Getter and setter methods in Java and property type in C# are called accessors. With accessors, you can give unified access to the user of your class.

C# is the programming language for the following example:

public class Automobile
{

int _weight = 200;
public int Weight
 

Get
{
   return _weight;
}

Set
{

   _weight = val;

}
}

There are a lot of things that you can do here in accessors code. You can do any validation before setting any value, you can update or calculate any other value or you can store/retrieve a value from storage devices directly from here.

Learn more about object-oriented programming here.

Sharing Responsibilities/Information via Communication

The primary purpose of OOP is to write huge software code easily. You divide a large problem into smaller problems and then write classes and create objects for those smaller problems.

But many people write one huge class and fill it with dozens of responsibilities. I believe that this is because people from the procedural programming background are unable to distribute responsibilities in different classes. You can solve this problem by distributing responsibilities among classes using association and inheritance.

Association

Consider there are two classes who does two different things. With association, one class uses the power of the other class to accomplish a common goal. This is it. The purpose of the association is sharing responsibilities.

e.g.

public class Member{


}

public Class Community{
Member aMember;

}

By having reference to another object your object has the ability to call the referenced object methods. You can say that both of these citizens have joined hands to accomplish a goal.

In this article, I will not tell you the intricate details of association, aggregation, and composition in the UML’s latest version or their differences. For me, association means sharing responsibilities between two classes. But if you are interested in minute details here is a good article on that.

If class A object is communicating with class B object to accomplish a goal then class A is dependent upon class B. Dependency is considered a bad thing in programming world (nobody like dependency in the real world too!). How to reduce this dependency and still make the objects work together as a team? This is the question for which many design patterns and principles are invented. I will discuss some tools to reduce the dependency later in the article but first discuss another tool which we can use to share responsibilities.

Inheritance

Inheritance is about distributing responsibilities between two classes: parent and child. The benefit is that the child class inherit all the qualities of the parent. As the child using parents capabilities hence it said that inheritance supports reusability.

Let’s see some examples of inheritance:

inheritance

 

As you can see that I have modeled the Vehicle class and it’s children so that the common features for both vehicles namely ‘car’ and ‘boat’ are combined in one parent class namely ‘vehicle’.

Now if I want another specialized car like a sports car I can extend the ‘car’ class and implement the logic specific to a sports car.

 

Nice hierarchy! It sounds logical and one cannot stand without cheering for the above design. But the problem is that real life problems are hardly like that. Real world problems are complex and any code that you write will evolve over time. Evolving requirements will cause evolving inheritance hierarchies.

I have seen systems where developers life is consumed in managing large hierarchies of inheritance.  Due to this, inheritance is not good for maintainability. But don’t underestimate the power of inheritance. There are some scenarios where using inheritance is natural such as WinForms.

Similiar to composition, there is the dependency between child and parent classes and dependency is a bad thing in programming. Now I will discuss how can you minimize the side effects of communication a.k.a dependency.

Reduce the Dependency While  Communication

Abstraction

Once my boss asked me to update one of my software. This update enables the software to receive data from network device as well as from serial device.

In order to implement this update, I need to take care of a lot of things. For example, I will have to include conditional statements to determine the kind of operation (serial or network) and update I/O methods since there are different methods for receiving data from a network device and a serial device. Hence this code is dependent upon tiny details.

But by using abstraction, I designed my code in a way that I can defer tiny details of implementation. I have abstracted out the tiny details and now my code depends upon abstraction. Therefore, my code will be updated easily with any new device code.

Hence his ability to communicate with any new code without hassles and dependency is achieved through abstraction. There are two tools of abstraction that I will discuss in this article.

Interface: First Tool of Abstraction

The concept of deferring the responsibilities to the implementing classes is called Abstraction and a tool for accomplishing this feature is ‘interface’ in Java or C#.

This is how I define the interface for the example described above:

Interface IStream
{

 byte[] getData();

}

Every class that implements an interface must define methods of the interface.

NetworkStream :IStream
{

 public byte[] getData()
 {
 
  byte[] data = NetworkCard.GetData();// read data from network
  return data;

 }

}

Here the ‘interface’ acts as an abstraction layer. It does not define the behavior or implements the behavior but give the hint or overall picture of how should a behavior look like (i.e signatures of methods). It defers the responsibility for defining the behavior towards the implementing class.

In above example, every class that wants to act like a Stream should implement the methods in the IStream interface. In this way, any piece of code that wants to work with network stream will talk to the interface of the implementing class. Here is the example code:

void CoreClassMethod()

{

IStream aDataStream =new NetworkStream(); // using the interface 

Byte[] data = aDataStream.getData();

Display(data);

}

Therefore, if in future my boss asks me to extend the capability of CoreClassMethod to handle PCI data. I will just write a new class that implements the IStream interface and then creates the instance of that class in CoreClassMethod:

PCIStream:IStream{

Public byte[] getData(){

// read data here using low leve I/O libraries and return it.

}

}

/////////////////////////////////////////
void CoreClassMethod()
{

IStream aDataStream =new PCIStream(); // using the interface
Byte[] data = aDataStream.getData();
Display(data);

}

The good thing is that the code that was written month before can work with the newly written code with minimal effort. There are many real-world examples of frameworks in frameworks such as ISerializable interface in .Net framework. Another good use of Interface is demonstrated in this article.

Abstract Class: The Second Tool of Abstraction

An abstract class is something in between a full-fledged class and an Interface. You can define some behaviors and defer some behaviors to be defined by its children.

For example:

abstract class GeometricalObject 
{

   void showOnScreen()
   {
   // implementation steps
   }

abstract void draw();
}

/////// Child 1: 
class rectangle: GeometricalObject
{
 void Draw()
 {

  //specifics of drawing a rectangle

 }
}

///////  Child 2:
class circle:GeometricalObject
{

 void Draw()
 {
  //specifics of drawing a circle
 }

}

Code that is shared among all children is written in the method showOnScreen(). The principle that makes all the above interfacing and abstraction possible is ‘Polymorphism’.

Polymorphism

In simpler words polymorphism is the ability of the parent reference to hold the reference to any of its children. A parent can be an interface, an abstract class or a full-fledged class. So when you call from parent reference the desired method gets called on the appropriate children. See the following code for the example of Streaming data.

Interface IStream
{

 byte[] getData();

}

/////////////////////////////////
NetworkStream :IStream
{

 public byte[] getData()
 {

  byte[] data = NetworkCard.GetData();// read data from network

  return data;

 }

}
////////////////////////////////
SerialStream :IStream
{
 public byte[] getData()
 {

  byte[] data = SerialPort.GetData();// read data
  return data;

  }
}

// Now if I have the reference of the parent class which in this case is IStream

// I can call the method of any child class

// e.g.

IStream anObject = new NetworkStream();

data= anObject.getData();

//Change this in the run-time

anObject = new SeriaStream();

data=anObject.getData();

So these are the basic tools for lowering damage done by communication between the objects. These tools help us reduce the dependency between objects.

Final Words

Hence, in this OOP article, I did not give you the index of definitions. But tried to give you a layout of OOP concepts that you can use to understand the most important concepts of OOP. This article answers most of the ‘Why’ question and a little bit of how questions. Why you need encapsulation? Why abstraction? How to communicate while reducing the side effects of communication. I hope this layout will give you a different perspective on OOP concepts.

Learn more about object-oriented programming with detailed examples here.

One thought to “Object Oriented Programming Concepts With a Systematic Approach to Write Better Code”

Comments are closed.