Article Outline:
- Who is This Article for? Students, Amateurs or Professionals?
- Where OOP stands in The Great Scheme of THINGS?
- Inside-Out Strategy: This Will Make it Easy for you to Apply These Concepts
- Inside the ‘Class’ Concepts
- Outside the ‘Class’ Concepts
- The Primary Goal Outside
- Association: How it is Better Than Inheritance
- Inheritance
- Method Overriding
- Abstraction: The Tool That Helps you Develop Mega Software Systems
- Interface: First Tool of Abstraction
- Closer Look at Interfaces
- Abstract Class
- Difference between Generalization and Abstraction
- Difference between Generalization and Composition
- Polymorphism
- Protected Variation: Ulitmate Goal
We often start our journey in programming by writing basic flow elements like variable initializations, conditional statements, loops and etc.
Then we move on and learn concepts of functions, passing arguments, global and local variables and so on.
Easy stuff for beginners.
Now if you are using good old ‘C’ language then you will move on to pointers and memory management.
With C programming knowledge you can conquer the world. You can work in embedded systems. You can write a new operating system or invent new programming languages.
But this will take time and you will have to be fluent in pointers and memory management.
For everyone else who is not serious about learning C then you have to be fluent in object-oriented programming.
Because if you are using Java, C#, python then object-oriented is a must. If you are using JavaScript or PHP then object-oriented programming can help you a lot.
And for those who are thinking of changing their careers get into the programming world then you will face object-oriented questions in interviews.
If you are a student then you will face interview questions about object-oriented programming.
Even if you only know about HTML and CSS3 and wanted to work as a front-end designer.
As you can see it is necessary to know about object-oriented programming for everyone(I am a bit conservated here let’s say 90% of developers).
I have seen hiring manager asking questions about object-oriented programming for an interview of the database manager.
So, object-oriented programming concepts are universal!
Who is This Article for? Students, Amateurs or Professionals?
Everyone! I mean everyone who studies computer science or programming studies object-oriented programming. TRUE!
But do we fully grasp the concepts of OOP? Think about it.
Well if you think that you succeeded in interviews where they asked questions related to OOP and now you believe are good in object-oriented programming. Don’t even think about it.
I aced all the question on object-oriented programming and answer all questions in all interviews. When I completed undergrad studies I had 5 appointment letters in my pocket from elite organizations.
The code that I have written at the start of my career and which I thought was a good quality code. Now when I see it today I feel vomit in my stomach and I hide it immediately before anyone can see it-yet I still see the developers making same mistakes that I have made over and over again.
Look getting work done is not enough. You can even exploit the object-oriented programming languages like C# and Java and use them as a procedural language. Getting work done without thinking about the quality of code will not make you a professional software developer.
Yes, I was getting work done but that was NOT according to the principles of object-oriented programming. So if you have good grades in courses related to object-oriented programming or if you have given all answers in an interview then you are still a long away from being a good object-oriented programmer.
Hence this article is for those who are currently writing software for money. Who have completed their studies and have at least 2 years of professional programming experience.
Why 2 years? Well at the start of your first job you are worried about proving yourself and learning the environment. Finding your tables and computer, knowing about the boss, learning the frameworks and tools that you never heard of in your studies.
Once you get it done(which takes around 2- 3 years) now you are looking ahead. Now you are ready to take those steps which will affect your programming career.
A quick test to know if you are good at professional object-oriented programming
Think of any famous framework in any programming language(javascript, Java, C#, PHP, Python). Think about all the constituent in that framework.
If that framework is no brainer to you. If you know why ‘clojure’ is used or why a particular set of classes are used or you know why you have to use so many classes to accomplish a simple task. Then consider yourself good at object-oriented programming.
A word of caution here. Above I am asking about the ‘why’ question, not the ‘how’ question. If you just know how to create a file by using the ‘Stream’ classes. Or just know how to call jQuery methods then you are a consumer of good object-oriented design. You are not the producer yet.
Do you want to be that vast majority of developers who write only glue code and most often tied to a framework for years? When they change their job then they realize that nobody in the universe is using that framework anymore and they have to start all again. I call them the consumers.
To be a producer you have to be on the other side of the wall where there are developers who not only understand why there is more than one class to accomplish a simple task but they are the ones who create libraries and frameworks that are consumed by millions of developers each day.
Are you ready to be the part of that small group of elite developers?
Yes, it is true that at the start your framework or library is not going to hit the life of millions of developers but if you start today it will improve the life of one developer. That one developer is you.
This will help you in two ways.
First of all, it will help your team understand and modify the code. And after 6 months It will also help you when you come back to change/update your code.
Second, it will help you to move up in the career ladder fast. You will become senior developer quickly and ultimately a great architect and system architect(provided that you choose to remain in technology instead of management).
Another benefit is you will not lose whatever you learn. If you learn a particular framework and work on that framework for two, three or even five years you know that the framework will be replaced by a more efficient framework.
Or your next organization is using a different framework than your previous work will not count as much. 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 experience.
Now you know why OOP is important. Let’s start our journey by understanding the context of OOP in the programming world.
Where OOP stands in The Great Scheme of THINGS?
This topic is to remove major confusions. People in development still have confusion about processes, architecture, databases and a lot of other things like frameworks and build process and etc.
All of a sudden one comes to you and ask where is this ‘OOP’ fits in the larger context of software development? Is it a process? Is it an architecture or something else?
For example, if someone asks you: Is OOP good for extreme programming OR SCRUM or let’s say an embedded system? Or ask you this question “does n-tier architecture supports object-oriented programming?”
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. Don’t trust me! You can ask any new developer you know the questions stated above and you will find them confused.
Now, what will you say when someone asks you this basic question:“What is object-oriented programming?”
Well if someone asks me then I will say that object-oriented programming is a development methodology. That was easy:) You probably know that.
Development Methodology
So why there is so much confusion out there. Let’s consider a developer named Jack. Jack is a new developer who has studied computer science or a related discipline from a college/university or online institution.
Jack know about object-oriented programming because he studied the course with the exact name:“object-oriented programming”. Jack believe this is the only way people write code. Jack doesn’t know much about assembly language or C programming language.
Jack started his career with JAVA or C# as a programming language. The mishaps that happen with Jack is that he was born into the programming world when everybody is talking about object-oriented programming and it is the only paradigm he sees everywhere.
Jack has no interest in history so he doesn’t know if there are other paradigms for development methodologies. Prior to Jack, there were other development methodologies that were so awesome.
Let’s take the paradigm of procedural programming. COBOL, Fortran, and Pascal were the default choices for any developer and before that assembly language programming was a must for every computer scientist.
Also, Jack doesn’t bother to look around. Jack doesn’t know there other fields where other types of development methodologies suits. For example, LISP a functional programming language and is used in artificial intelligence systems. Although it is not limited to that only and there are other applications where LISP can be used.
Even today the procedural programming language ‘C’ is most suitable for embedded development.
So, let’s say goodbye to Jack for now. I believe that now Jack knows that object-oriented programming is one of many development methodologies. It has nothing to do with development processes or architectural style.
Also, one can use any development methodologies with any development process. Similar is the case with architectural style. One can use any development methodology with any architectural style.
But, there are some methodologies that can best work with some development processes and architectural style. But no one is going to stop you if you try to break the established guidelines. After all, creativity is what a developer should be looking for.
Now, for the sake of completeness let us discuss the development processes, but this time for professionals only. Also, remember that the right process with the right methodology will lead to a good quality software code. Here is an example of how to use both together.
Development Process: Why There is no bad Process
If you have studied software development process as course then I can bet that you hate waterfall model.
Waterfall model has become a kind of punching bag. Everybody who sings for agile methodologies, first show his hate for the waterfall. It goes something like that:
“Look at that waterfall model- it’s all waste. You develop a system without customer feedback and now it is of no use- all the useless documentation and code is going to the bin ” or something along these lines.
I have been like that until one day I realize that there is no software process in the organizations where I worked. I researched and I found out that there are very few organizations that adopt any development processes in its true sense.
For the rest us there is only one process and that is what I called the brute force software development process. Your boss gives you a task or even a complete project and you have to complete the task and report to the boss.
Someone higher in the chain run the build process and someone from QA test the software.
Or there is an amalgamation of good practices from different software development processes. Sometimes there is automated testing in the place. Sometimes there is pair programming borrowed from XP, sometimes there is short release cycle and continuous build borrowed from SCRUM.
What processed you or your organization follow depend upon you and your team. So don’t get offended if someone tells you that we use this sophisticated process model and you don’t. Even the waterfall model is good enough for me if you just remove the documentation because I hate documentation.
Even I have devised my own process model. You may like it (or hate it).
Now let’s move to our core topic and that is the strategy that I will use to describe object-oriented programming.
Inside-Out Strategy: This Will Make it Easy for you to Apply These Concepts
I will start with the internals of the core entity in object-oriented paradigm and that is the ‘Class’ and it’s representation in memory and that is the ‘Object’.
In the ‘inside’ strategy I will discuss only the internal of object and classes. Nothing more. If you do the basics right then everything else will be fine.
I will only discuss internals that is necessary to know for any professional developer. There are chances that you have learned these out of your own curiosity but I will share my experiences.
Once you mastered the internals of the class and objects then we will move to the ‘out’ strategy. This is where one object or class work in conjunction with other object and class.
‘Out strategy’ is a very important part. Because in order to achieve something bigger every object in your software code needs to communicate with each other.
There are a lot of principles and design patterns to achieve this inter-object communication but I will tell you the most important principle that you need to know at this stage.
After that, I will discuss that it is not only how your objects collaborate with one another but how you collaborate with others specifically your teammates and your boss.
This is an important point and many people ignore this but for professional developers who are working in a professional environment and not in a classroom will face these challenges.
Hence the inside strategy comprise of:
Class, fields, functions, constructors and static fields. I will explain an important concept of how objects are represented in memory. I will also discuss how to create the class that looks like created by a professional.
The out strategy consists of two concepts. The first concept is about how your classes interact with each other and the ideas that are essential for professionals. Second and the most important concept in ‘out’ strategy is how you communicate with every other human around you.
This means how to communicate your design ideas with your teammates. How to take your teammates onboard with your ideas and most importantly how to convey your ideas to your boss.
The last part is important because when you talk about improving the quality of your work or introduced methods that will improve the efficiency not in the short term but in the long term then everybody– I mean everybody– will resist it.
Nobody wants a quality code initially. They need the job gets done. In their heads, they think job to get done equals to quality code. This looks good initially but in the long term that code will grow and become rotten and then everybody in your team will feel the smell of that rotten code.
There are tools to deal with that situation but for now–let’s assume that you want to know how to start software development with the right mindset.
Inside the ‘Class’ Concepts
Class: Your Tool for Capturing ideas
A class represents your ideas about ‘anything’. Textbook definition is that the class is ‘blueprint’.
A class can represent a physical object like chair, screen, humans, animals.
A class can represent a role: Student, Employee and etc.
A class can represent an abstract concept like maths concepts: Circle, Kalman filter, and other. A class is your idea of ‘anything’ and how do you want to represent your idea in the computer memory.
Object-oriented programming gives you tools to define your class. These tools are the class name, data, and behavior.
You can represent the data of your ‘concept’ in a class. That data is called attributes. It can be of any primitives data types in the programming language you are using. For example, it can be, int, double, float, long, byte, short, boolean or char.
A class also represent the behavior of your idea. The way you want your ‘idea’ or ‘thing’ want to behave you can model in your class.
It is not necessary for you to create the behavior or data. It all depends on your idea. It is your choice if you want to create a class with behavior only or a class with data only or a mix of both.
You have made your choice and now let’s move on to the real thing that will transform your idea into a reality(in a computer memory)- the object
Object: The Real Thing
The only thing that exists in memory is an object. An object is created from the definition of class and here is the example of how the object is created:
MyClass theObject = new MyClass();
Objects are the real thing because they exist in memory. Let’s explore more on this and consider the following class:
public class Automobile { int NumberOfWheels = 4; int Weight = 200; double fuelEfficiency = 1.2; }
Now calculate how much memory the object of this class will take?
int is 4 bytes and double will take 8 bytes if you are using C# or Java. Therefore one object of this class will take 16 bytes.
If you create 2 objects of this Automobile Class it will take 32 bytes.
What if a naive developer fetches records from a huge database and created the objects for each record of ‘Automobile’. When will it run out of 4GB of memory?
No of Records that your memory can hold = 4GB/16
Hence after 67108864 records, the system memory will be filled up. In a professional environment, databases are usually way more size than this. I have seen a junior developer doing this kind of mistakes when they are new to object-oriented technology.
The solution for a junior developer is that you should use ORM framework for that and that will handle these issues for you by managing the memory.
Let’s consider another example of object:
public class Automobile { int NumberOfWheels = 4; int Weight = 200; double fuelEfficiency = 1.2; static int countVehicles =33; }
Now, what will be the size of one object? 20 bytes. What will be the size of 5 objects?
The answer is 84 bytes. 16*5+4 = 84. There will be only one copy of the static variable in memory. It does not matter how many objects you create there will be only 1 copy of the static variable that will exist in memory.
In addition to that, that single copy of the static variable is accessible to all the objects. It’s kind of a global variable. Yes, the bad-old global variable.
One thing that I learned from painful experiences is to avoid the use of global variables. As a program grow older, it is difficult to track that who is modifying the value of global variables. So always be careful when using static members in a class.
Class: Member Variables
Member variables hold the current state of an object. These are the data variables and they are also called instance variables. If they are declared with the static keyword then they are called Class variables. Well, you know all this–Don’t you?
The key to using member variables is how will you use them in your code. If you intend to use a member variable within a class then there are very few problems.
But if you want –maybe someday– to expose your member variables outside the scope of your class then you should follow certain guidelines. Outside the scope means writing a class to disk in JSON format or a representing a database record or communication with another class.
For these outside reasons, people have developed getter and setter methods in Java and property type in C#. They are also called accessors. These accessors play an important role in frameworks and they are extremely useful concepts.
Consider C# as the programming language for the following example:
public class Automobile { int _weight = 200; public int Weight Get { return _weight; } Set { _weight = val; } }
Now what you are seeing is how most people use these accessor methods(get and set). There are a lot of things that you can do here. 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.
The most important thing that these accessors do is that they signal outside world (especially frameworks) that we exist. Through accessors, the outside world knows how many getters and setters are there and they will behave accordingly.
Here is an example of how an outside class can use accessors:
public void methodInAnotherClass() { Automobile theAutomobile = new Automobile(); theAutomobile.Weight = 300; // retrieve int currentAutoWeight = theAutomobile.Weight; }
Class Behavior: Methods, Overloading, and Constructors
Methods define the behavior of your class provided–if your class has any.
You can define a class with methods in it or you can create a class with data only. There is no shame in this. You know how to define a method or how to write a signature. The only problem here is what behavior your class should have?. I will address this problem in the second part of this article.
Method overloading is when you define two methods with the same name but with different parameters.
e.g
int GetVehicleEfficiency(int weight) //ok int GetVehicleEfficiency(int weight, string engineType)//ok int GetVehcileEfficiency(float weight)// Great float GetVehicleEfficiency(int weight) // Not OK you cannot change return type. This will confuses the compiler
This sounds like a great feature to have but should you use it. I would say that you should avoid it–Why?
It always confuses me if I declare two methods with a different number of parameters but if you keep the no of parameters same and change the type of parameter then method overloading is of great use.
Hence always avoid confusion while programming because it will make you drag you.
Let’s talk about constructors:
A constructor is a specialized method with the same name as the class and every class that you create has one default constructor with no parameters.
Class MotorVehicle{ String engineType; // rest of the class code.. } // The default contstructor MotorVehicle aVehicle = new MotorVehicle();
You can create an object in many ways by overloading the constructor:
Class MotorVehicle{ String engineType; MotorVehicle(){ engineType =default; } MotorVehicle(String anEngineType) { this.engineType= anEngineType; } } // creating objects MotorVehicle aVehicle = new MotorVehicle(); MotorVehicle aVehicle = new MotorVehicle(“Diesel Engine”);
Also, avoid using many constructors approach because this will also create the confusion and ultimately drag you.
You can see that there are features that are available to you but there are people who are ahead of the game like uncle Bob and Martin Fowler. They teach us some principles and patterns which tells not to use some features and use other features in a certain manner.
Why?
These patterns and principles given by seniors are a great way to avoid mistakes. You have to learn them if you want to be in the league of elite developers.
Another such suggestion (which also restrict you to use some features ) is to avoid setters methods or avoid changing the state of an object and this leads to another advanced level concept for professional and that is immutable objects.
Immutable Objects: Advance Tool for Professionals
An immutable object is an object whose state cannot be changed after it is created. With immutable objects, if you want an object with the different state then you will have to destroy the old object and create the new object with the desired state.
How can you create an immutable object?
Don’t let anyone change the state of an object and one way to this is: don’t provide any setter method for the object.
Making all data member private i.e only accessible within the class.
There are other sophisticated methods to create immutable objects such as factory method to create objects but for now, keep it simple.
Example of immutable object:
One example of an immutable object is String object in C#.
String data="Work"; data.toUpper(); Console.Writeline(data); // This will print: "Work" String anotherData = data.toUpper(); Console.Writeline(anotherData); // This will print:"WORK" Console.Writeline(data); // This will print the original: "Work"
As you can see that when method ToUpperCase() is called, it does not change the underlying string. But it creates another object with the modified string as shown in the second line. Therefore strings in C# (even in Java) are immutable objects.
But why use the immutable object?
Why I choose the discussion of immutable objects here. I can easily flash around a few definitions of objects and classes and move on but this article is written for people who are ahead of college kids and have a certain level of programming experience and they want to move ahead.
When you are in the league of elite developers you have to faced the challenges of multi-threaded programming and I have seen so many experienced developers failing on the battleground of multithreading.
Therefore, the immutable object is a tool that you can use in multi-threaded programming. Because immutable objects are thread-safe. How to use them in multi-threading is out of the scope of this article but add this tool in your toolbox so that when you work on a multi-threaded application then you can pick that tool and use it.
Encapsulation
People called it information hiding even some people go ahead and called that it is good for security. But both of these terms as I recall from my experience are misleading.
From information hiding, it seems like an object is not going to share data with other objects but this is not the case. An object should share data and/or responsibilities and without sharing there is no use of an object. Let me share a personal story.
If you have worked in a software developer where demos and trade shows are important for marketing you know that demos are important.
On such demo day, there was an urgent requirement to change the display of a software and I was asked to make the change. There were other engineers involved in that product.
The change was small. I have to add two fields to the display panel. I create another class and since both of these parameters were related therefore I put them in a single class and use the object of that class.
I did this to make the user interface code to look cleaner. Because in such a stressed situation (the night before the demo) you cannot afford to make tiny mistakes.
The code worked and one of the engineers praises me in such a way that I still remember that after so many years. He told me that “Wow you created a new variable and use that!”
See, he is telling that an object equals variable. First of all, I don’t want my readers to be like that i.e treating an object like a variable. Beside that this story depicts the concept of encapsulation.
You merge two or more data and/or functions into a single entity(the variable). This is called encapsulation.
Hence the concept of encapsulation is more towards modularity then security or hiding something. It is more towards making an object/class represent a single modular concept. Hence use it in that way.
Naming: So that you can Read Your Code after 6 Months
It is a good place to talk about naming when we are discussing the internals of the class and objects. As a professional developer how you should properly name your class, member variables, and member functions.
As a rule, you should name your function and variables in such a manner that there are no needs for comments. How?
As a professional you know that most of your time is spent maintaining the code that you have written. This includes fixing bugs, making improvements, adding features and using your code written for one project to other projects.
Therefore it is important for you to write code that is easy to understand for you or for any other developer. One way to achieve this is through comments. You can write comments to elaborate your code.
Another better approach is to name your variables and function in such a way that there is no need for comment.
For variables use elaborative names. Never use short names e.g. You can only use short names(i,j,k) in the loops e.g.
In order to do that you will have to make your function shorter.
If you have a large function currently then divide it into multiple small functions. Each function can contain only 3-5 lines. It looks like an exaggeration but you get the idea. Small enough functions whose purpose can be defined in their name.
Example:
// Descriptive and meaningful methods and variable and class names int GetProcessedData(); void TransformAllPositions(); int endingFrameLocation; int firstPositionInDatabase; class BodySearcher {} class FileParser {}
In this way your class name, variable names and function names will convey the reader of your code about the minute detail and will help him understand the code better.
For now, this is enough for inside the class concepts. Now let’s move to concepts outside the boundaries of class.
Outside the ‘Class’ Concepts
If you are writing a professional code then one class or one type of objects will not be sufficient. You need more than one classes and these classes have to interact with each other to accomplish a common goal.
The Primary Goal Outside
Consider classes and their objects as the first-class citizen in the object-oriented paradigm. Each citizen has different responsibilities. Each citizen will interact with each other to achieve a primary goal.
As an object-oriented developer, your job is to share the responsibilities among the citizens and design the interaction channel among the citizens in such a way that it is simple and effective.
There are many tools to share responsibilities between objects. A famous technique is ‘inheritance’. Responsibilities are shared between children and parents. There is a better approach than inheritance and I suggest you as a professional developer you should use that approach.
Extremely important concepts like interfaces and abstract classes are basic for understanding any framework an even designing your own framework.
Next concept is polymorphism and how you can leverage polymorphism to write code that is easy to change and maintain.
Finally, all of this discussion will lead to a very important principle of communication between objects. This is the source principle for many object-oriented design patterns. This is also the base principle for concepts like interfaces and polymorphism. It is called the protected variation.
Therefore you will know why any design pattern exists or even concepts like polymorphism and interfaces are there to support protected variation.
So, let’s move on with our most important tool outside the scope of ‘class’.
Association: How it is Better Than Inheritance
The citizens of our object-oriented paradigm can develop a relationship using the ‘association’. In very simpler words it’s like having a reference to another object.
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.
There are certain nuances to association namely aggregation and composition.
The differences are easy to understand if you consider the life of an object. For example, consider two objects A and B. If A holds a reference to B and both can live independently then it is called the good old association. This also means if object A is destroyed(and garbage collected) then there is no effect on object B.
The relation is called aggregation if object A holds more than 1 references to object B or there is a part-whole relationship.
The composition is when the referenced object’s life depends upon the referencing object’s life. For example, if object A creates the object B. Therefore when object A is destroyed then object B also go into the valley of dooms.
But don’t worry about all these differences because when programming you will not be worried about the type of association. When you are doing real-world programming you are worried about how the responsibilities among the classes should be distributed.
You will be worried about how your objects communicate with each other with minimal discomfort. How can you optimize the communication between objects?
Association is a tool that you can use to make objects share their responsibilities with each other and another such tool is inheritance.
Inheritance
Inheritance is about distributing responsibilities between two classes: parent and child. One benefit is that the child class inherit all the qualities of the parent. This feature alone makes inheritance a lucrative choice and the foundation of that is reuse.
Let’s see some lame examples of 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.
It sounds logical and one cannot stand without cheering and clapping for the above design. This is how you read in other blogs and books. This is good for a beginner. But the problem is that real life problems are hardly like that.
Real world problems are complex. Real life problems evolve. Therefore if you are using inheritance to model real problems these hierarchies will also evolve.
I have seen systems where developers life is consumed in managing large hierarchies of inheritance. Managing inheritance hierarchies is a cumbersome task. If you don’t believe me then try using inheritance for next 6 months in your current project and you will know why it is a rigid approach. On the other hand, composition is more flexible in adopting changes.
I am not saying that inheritance is altogether bad and you should not be doing it. But as a beginner, the inheritance look charming as you can see the above vehicle and car example. This leads to misuse or overuse of inheritance.
There are some great uses of inheritance and there are some drawbacks to the composition. But for beginners and for a clean code you should focus more on composition instead of inheritance.
Method Overriding
Before moving on let me introduce another important topic that is important for sharing responsibilities between objects and that is very necessary to understand some advanced concepts.
Method or behavior overriding is that when child class re-implement the parent class behavior in its own way.
There is a car which has the ability to drive. Then there is a specific car which is the sports car. It can drive but it’s driving feature is a bit specialized that it has more engine power. Hence method overriding let the child demonstrate relatively same behavior but in a more specialized way.
Abstraction: The Tool That Helps you Develop Mega Software Systems
In outside strategy, we have discussed methods to distribute responsibilities to different classes. But sharing responsibilities between objects blindly will lead to a complex design.
As a professional programmer, one of the major goals is to reduce the complexity of the system. This single skill will separate you from those who write spaghetti code.
Let’s understand abstraction with my personal story. Once my boss asked me to update one of my software. This update requires that software should be able to receive data from a network device. Previously it was able to receive data from serial port only.
There are going to be a lot of details to take care of. For example, I will have to include some conditional statement to determine the kind of operation (either serial or network) and I will also have to include/change low-level I/O methods since there are different methods for receiving data from serial and network devices.
These tiny details are good enough to drown me and resist my ability to think horizontally. For example what we can do if the software can acquire data from a network device. What we can do with this new data rate and so on.
By using abstraction I have designed my software in such a way that supports horizontal thinking.
So, as soon as my boss asked me for new changes I don’t’ think about the tiny details. I know my code can talk to any device. This gives me the power of horizontal thinking.
This horizontal thinking allowed you to solve problems and come up with creative solutions without getting involved in petty details and I consider abstraction as a tool of object-oriented programming that helps you achieve precisely that.
Let’s talk about the tool itself:
Interface: First Tool of Abstraction
The first tool that I will describe is the ‘interface’. This is how you define it:
Interface IStream{ byte[] getData(); }
You cannot instantiate an interface. 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; } }
Easy? I believe you know this. Simple syntax stuff. The good part is where I told you that you cannot create the instance of an interface. There is no way your interface will ever see the life of its own that is it will never exist in computer memory. Only the implementing class’ object is going to see the light of life. Only the object can exist in memory.
Here an interface acts as an abstraction layer. It does not define the behavior or implement the behavior but give the hint or overall picture of what should a behavior look like(i.e the signature of the methods). It gives the responsibility for defining the behavior towards the implementer.
For the above example, every class that wants to act like a Stream should implement the methods in the IStream interface.
In this way, any of your code that wants to work with network stream will talk to the interface that of the implementing class. Here is the example
void CoreClassMethod() { IStream aDataStream =new NetworkStream(); // using the interface hold the / //reference Byte[] data = aDataStream.getData(); Display(data); }
Therefore if my boss asked me to extend the capability of CoreClassMethod to handle PCI data. I will not worry about the implementation of CoreClassMethod. I will just write a new class that will implement 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(); Byte[] data = aDataStream.getData(); Display(data); }
In this way, I can extend the capabilities of the existing code. Another good use of Interface is demonstrated in this article.
Closer Look at Interfaces
Let’s take the example of.Net library’s interfaces ISerializable or IDispoable. If any of your class implement any of the above interfaces then it should define the methods of the interface.
Any Other part of the .net library that works with Serializable objects (e.g .net JSON library) will work seamlessly with your objects as well. Because now you have implemented the required serialization in your own manner in your own class.
The beauty is that the code was written years before can work with your code that you have written recently.
Let’s explore more on this concept in the next tool of OOP for abstraction.
Abstract Class
An abstract class is something in between a full-fledged class and an Interface. You can define some behaviors(methods) and leave some behavior to be defined by its children.
For example:
abstract class GeometricalObject{ void showOnScreen(){ // implementation of .. } abstract void draw(); } ///////////////////////////////////// class rectangle: GeometricalObject{ void Draw() { //specifics of drawing a rectangle } } ////////////////////////////////// class cricle:GeometricalObject{ void Draw() { //specifics of drawing a circle } }
Some code that is shared among all the children(implementers) is the code written in the method showOnScreen in the parent class.
Difference Between Generalization and Abstraction
The concept of sharing common behavior of children in the parent class is the essence of inheritance or generalization. The primary tool to accomplish this is inheritance.
The concept of delegating the responsibilities to the implementing children or classes is called Abstraction (and sometimes specialization). The primary tool for accomplishing this feature is ‘interface’.
The abstract class stands in between these two extremes. This tool allows some behavior to be shared among all classes and delegate some behavior to the children classes. There are great applications of ‘abstract class’ in developing frameworks. I have discussed this in detail in this article.
Difference Between Generalization and Composition
In generalization(and inheritance) common behavior between two children is defined in the parent class. Therefore anyone who is using the children will have access to all the methods of parents. You have reused the code means you don’t have to write the code twice. But the drawback is that you have to deal with strict hierarchies of inheritance. Hence it is not flexible.
Now with composition, you can achieve the same. You can combine a behavior in a class and then give the reference to every other class who need that behavior. This is more flexible. You can change the reference at run-time while in inheritance you can not change the hierarchies at run-time.
Therefore it is recommended that you should achieve reusability through composition rather than inheritance.
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(a.k.a base class).
So when you call from parent reference the desired method gets called on the appropriate children.
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();
Polymorphism not specific to inheritance or to interface or abstract class. It’s a generic tool that can be applied to inheritance, abstract class, and interfaces via method overriding.
Another generic concept which is influence many concepts of object-oriented programming is protected variation.
Protected Variation: Ulitmate Goal
Many concepts of object-oriented programming that we discussed above are techniques for achieving protected variation.
Recall the example from the discussion above when my boss asked me for receiving data from a network stream.
It does not bother me much to make the change because I protected the variation in the data receiving method using the abstraction and polymorphism.
This is because I anticipated this kind of change. In a similar manner, I used polymorphism and abstraction where I anticipate a change in the future. Therefore when the change is requested it is easier to implement the change.
Hence you can keep in mind the variations that your software may face and then use interfaces and polymorphism to protect it from changes and variations.
A word of caution–don’t overdo it. It is a design principle and that is in your hand to abuse it or use it consciously. Don’t assume that every aspect of your code will change. Because protecting the variation incur cost in terms of more code or classes and ultimately complexity.
Therefore if you over do it then you will have to manage a lot of code without any good reason. So when you are protecting the variation then make sure that there is some merit to your decision.
Finally, in the outside strategy, you learned tools for assigning responsibilities to your first class citizens.
Excellent job!
great article i suggest to start a youtube channel and start a topic on domain driven design which is being current days
Thanks, adam. I will create videos for my readers soon.
-Umair