Object Oriented Programming – Structure
OOP is a paradigm where code is organised to represent the objects or entities being modelled and interacting with a system.
At a very basic level, classes are created, which serve as definitions describing the data (attributes) and methods (things it can do) of an object. An object is anything that needs modelling, storing or manipulating in a software system. Once a class has been created, copies of it called instances can be created and used. A class itself holds no data: it just lists the attributes that can be used for storage. Once instances are created, those instances can hold data.
OOP takes this much further – see Object Oriented Programming – Features for a full list.
Despite being a programming paradigm in itself, code for OOP is also procedural – the same basic rules of procedural programming still apply.
An OOP example
As you have seen in the section covering procedural programming, there are a limited number of programming keywords. It is the combination and ordering of multiple commands that creates a software program. Add in variables which allow you to track and change values, and we can create very powerful pieces of software.
One of the big problems with programming is that it does not relate in any way to the real world. Consider writing a piece of software to allow travel agents to book holidays. Some of the entities (things) of interest to that system will include:
- Clients (the people going on holiday)
- Hotels being stayed at
- Flights being booked
- Tours taken while on holiday
Each of those four items is a complicated construct: a person has many attributes. A hotel can’t be described in a sentence. A flight has a number, departure date, departure airport, destination airport, a whole array of different seats and so on. Trying to represent these complex structures using strings, integers and boolean values can become difficult, resulting in slower development, and a more error-prone system.
An OOP approach sees things differently. It sees that there are the four items described above. (There would be more, but for simplicity we will stick with them). Each entity is treated as a distinct unit, and characterised based on what attributes it contains, and what methods it can perform. With the ‘client’ entity, we might decide that we need the following attributes:
- Forename
- Surname
- Title
- Date of birth
- Which flights they are booked on
Notice that the first four of those attributes are simple data types (string, string, string and date). The fifth looks unfamiliar: in this example, it would be a list of flights – flight being a new data type that we would create, in the same way as we’re creating the client datatype now.
We would also need to decide what functions a client object should be able to perform. We might go with:
- Set forename (use code to set the forename of a client)
- Get forename (use code to retrieve the forename of a client)
The list could be expanded for the remaining attributes.
Below are two code snippets that illustrate how the code would look based on an OOP and non-OOP approach to processing details for two customers.
Non-OOP approach
//C# string client1Forename = "Tom"; string client1Surname = "Smith"; string client1Title = "Mr"; Date client1DOB = "20/04/1990"; string client2Forename = "Tomasina"; string client2Surname = "Smith"; string client2Title = "Mrs"; Date client2DOB = "02/05/1992"; //Call a function to save the person SavePerson(client1Forename, client1Surname, client1Title, client1DOB); //Now I need to create a SavePerson function //But I won't; it's just an example
OOP approach
C# Client c1 = new Client(Forename="Tom", Surname="Smith", Title="Mr", DOB="20/04/1990"); Client c2 = new Client(Forename="Tomasina", Surname="Smith", Title="Mrs", DOB="02/05/1992"); c1.SavePerson(); //Saves 'c1' client data c2.SavePerson(); //Saves 'c2' client data
Comparison
Clearly, the OOP code is far clearer and easier to follow. What isn’t quite as obvious perhaps is the way in which the methods and data are ‘tied’ together. In the non-OOP approach, there is a SavePerson function, but it requires the parameters of the client to be supplied, and it is used for every single client. In the OOP version, each instance of a client (so c1 and c2) both have their own ‘SavePerson’ function, associated with their own set of attributes. This allows us to have objects in our code (like c1 or c2 in this example) that are complete packages – they contain the attributes and the methods that it can use. Every instance of the object has its own set of attributes and own set of methods. This principle is called encapsulation.
Benefits
An OOP approach leads to much more readable code – just see the difference in the two examples above.
More fundamentally, it makes it easier for developers to work together. OOP also introduces the concept of data-hiding. In the example above, it is clear that the clients c1 and c2 are going to have their data saved. Do we know how that is going to happen? No, and we don’t care – all that matters is that it works. Unless we are responsible for developing that functionality, all we need to know is that it works, and not how it achieves it. Because of the encapsulation, it is easy for one developer to create a class defining one entity, while another developer works on a different class.
If we were not using an OOP approach, we would need to add in routines to allow the client data to be saved, and this would immediately require us to be involved to an extent with that functionality. We would also need to ensure it was duplicated in any code where we might need to save the client’s details.