Programming Concepts: Object-oriented programming (OOP)
Object oriented programming is a type of programming paradigm based around programming classes and instances of classes called objects. These can be objects that appear on the screen (e.g., pictures, textboxes, etc.) or are part of the programming (e.g. actors, connections, particles, etc.).
Structures are very similar to Classes in that they collect data together. However, classes extend this idea and are made from two different things:
- Attributes - things that the object stores data in, generally variables.
- Methods - Functions and Procedures attached to an Object and allowing the object to perform actions
Let's take a look at the following example:
class car private maxSpeed as integer public fuel as integer public sub setSpeed(byVal s as integer) maxSpeed = s end sub public function getSpeed() as integer return maxSpeed end function public sub refuel(byVal x as integer) console.writeline("pumping gas!") fuel = fuel + x end sub public function getFuel() as integer return fuel end function public sub drive() fuel = fuel - 1 end sub end class
You can see that the class is called
car and it has:
- two attributes:
- five methods
- three procedures:
setSpeed, refuel, drive
- two functions:
- three procedures:
Remember this is a class and therefore only a template, we need to 'create' it using an object
These store information about the object. In the example above we store the fuel and maxSpeed. The attributes are attached to the classes, and if there are several instances (objects) of the classes then each will store its own version of these variables. Note that instead of the usual dim, there is the word private or public, we'll cover that in the encapsulation section.
Unlike structures, OOP allows you to attach functions and procedures to your code. This means that not only can you store details about you car (the attributes), you can also allow for sub routines such as
refuel, which are attached to each class.
methods and attributes
structures don't have methods
OO - PIIE
When talking about OOP you must remember the following:
- 00 = Object Orientation and
- PIIE = Polymorphism / Inheritance / Instantiation / Encapsulation
As we have seen a class is a template for something, you can't actually execute a class, you must instantiate it, that is create an instance of an class in the form of an object.
dim polo as new car 'instantiation 1 dim escort as new car 'instantiation 2
The code above creates an object called polo and escort, both of class type car (which we declared earlier). We can now use all the public attributes and methods:
polo.refuel(100) 'assuming fuel starts at 0 polo.drive() escort.refuel(50) 'assuming fuel starts at 0 escort.drive() for x = 1 to 20 escort.drive() polo.drive() next polo.refuel(10) console.writeline("polo: " & polo.getFuel()) console.writeline("escort: " & escort.getFuel())
This would output the following:
dim beetle as new car 'instantiation
You noticed that we didn't have to use the dim statement for the attributes and we used the word
private instead. What this means is that these attributes are not directly accessible once you have instantiated the class. Let's take our polo class as an example:
polo.fuel = 100 'this would be acceptable (but not in the exam!)
In the example we access the fuel attribute of the polo class and give the car 100 units of fuel because fuel is declared as public, there are no restrictions in accessing it. However, when we try the following we run into trouble:
polo.maxSpeed = 100 'this would be unacceptable
The reason that this wouldn't work is because we have declared the maxSpeed attribute as private. If something is declared as private you can't access it externally, but how do you access it? The only way to access a private method or attribute is to use an interface, or public method. In the car code example we have:
public sub setSpeed(byVal s as integer) 'declaring an interface maxSpeed = s end sub
Because this method is public we can call it through:
polo.setSpeed(100). And because setSpeed is declared inside the car object, it can have access to all the private attributes and methods.
We also need to find out the speed of a car to display to the user, we can do this by creating a get routine:
public function getSpeed() 'declaring an interface (a function as we are returning a value) return maxSpeed end function
Because this method is public we can call it through:
polo.getSpeed(). And because getSpeed is declared inside the car object, it can have access to all the private attributes and methods.
In general attributes should always be declared as private and only accessible through interfaces, using a setX command to give the private variable X a new value, and using the getX command to return the value of X. You should never directly access X!
Declare a colour attribute for the car that can only be accessed through an interface
private colour as string 'this must be private!
public sub setColour(byVal c as string) 'declaring an interface, make sure it's public! colour = c end sub
public function getColour() 'it must be a function to return a value return colour end function
1 Class actor 2 Private health As Integer 3 Private name As String 4 Private x As Integer 5 Private y As Integer 6 7 Public Sub setName(ByVal p) 8 name = p 9 End Sub 10 11 Public Sub walkforward() 12 x = x + 1 13 End Sub 14 15 Public Sub eat() 16 health = health + 10 17 Console.WriteLine("Nom Nom Nom") 18 End Sub 19 20 Public Sub gethit() 21 health = health - 10 22 Console.WriteLine("Argh!") 23 End Sub 24 25 Public Sub displaystats() 26 Console.WriteLine("Character :" & name) 27 Console.WriteLine("Health :" & health) 28 Console.WriteLine("Location :" & x & ", " & y) 29 End Sub 30 31 Public Sub setHealth(ByVal p) 32 health = p 33 End Sub 34 35 Public Sub setLocation(ByVal px, ByVal py) 36 x = px 37 y = py 38 End Sub 39 40 End Class
dim wizard as new actor 'it doesn't have to be named wizard, it could have another name dim orc as new actor 'it doesn't have to be named orc, it could have another name wizard.setName("Barry") 'remember to use your get and set routines! wizard.setHealth(100) wizard.setLocation(4,5) orc.setName("Herbert") orc.setHealth(35) orc.setLocation(20,2) orc.displaystats()
Encapsulation is such a common thing that some languages have short cuts for making get and set routines. In VB.NET this involves using a
Private _fuel As Integer Public Property Fuel() As Integer Get Return _fuel End Get Private Set(ByVal value As Integer) _fuel = value End Set End Property
As we will never call
lada.fuel = 23 Console.Writeline(lada.fuel)
Building on the car example above, what would happen if we wanted to declare an electric car? Well we'd probably want to store some information on the number of batteries that it has:
class electricCar private maxSpeed as integer private fuel as integer 'fixed! private numBatteries as integer 'added public sub setnumBatteries(byVal n as integer) numBatteries = n end sub public function getnumBatteries() return numBatteries end sub public sub setSpeed(byVal s as integer) maxSpeed = s end sub public function getSpeed() as integer return maxSpeed end function public sub refuel(byVal x as integer) as integer '..... 'HOLD ON! end class
This seems like a very long and tedious task rewriting all the same code again. You're right! It would be far better if we only had to declare all the new stuff we wanted to add. OOP allows for inheritance, where a new class can inherit the attributes and methods of a parent class:
class electricCar inherits car 'declares what attributes and methods you are inheriting private numBatteries as integer 'added public sub setnumBatteries(byVal n as integer) 'interface numBatteries = n end sub public function getnumBatteries() 'interface return numBatteries end sub end class
This means that everything that car declared is now accessible from electricCar, as well as the new numBatteries attribute and methods. Let's instantiate this example and see what's possible
dim gwiz as new electricCar gwiz.setnumBatteries(6) 'from electricCar gwiz.setSpeed(60) 'from car gwiz.drive() 'from car
By using inheritance it makes creating new classes very quick and easy. It also allows for a modular approach to creating classes, where you might never use the base class at all, but only as a means of creating other child classes.
Rather than having to rewrite the same functionality for similar objects, OOP allows you to reuse attributes and methods from parent classes.
class limo inherits car 'declares what attributes and methods you are inheriting private numSeats as integer 'must be private private colourSeats as integer 'must be private public sub setnumSeats(byVal s as integer) 'interface set numSeats = s end sub public function getnumSeats() 'interface get return numSeats end function public sub setcolourSeats(byVal c as string) 'interface set colourSeats = c end sub public function getcolourSeats() 'interface get return colourSeats end function end class
Creating new classes from parent classes is very quick and easy. It allows for a modular approach to creating classes, where you might never use the base class at all.
When you were young you might have watched the Mighty Morphin' Power Rangers. These guys could morph from regular people into their power suits. Sadly polymorphism isn't that exciting, but it does allow you to change the function of attributes and methods when you are inheriting from a parent class. Consider our car example again. When we created the
electricCar object we inherited from
car and added the
numBatteries attribute and methods. But what happens when we try and refuel, let's take a look at the code:
public sub refuel(byVal x as integer) as integer console.writeline("pumping gas!") fuel = fuel + x end sub
Well this just won't do. We are creating an electric car and we don't want to say that we are pumping gas; what would our sandal-socked yoghurt eating friends say! So for the
electricCar object we want to inherit everything from
car, but we want to morph(change) the
refuel method. To do that we are going to use something called override:
class electricCar inherits car private numBatteries as integer public sub setnumBatteries(byVal n as integer) numBatteries = n end sub public function getnumBatteries() as integer 'interface return numBatteries end sub '###### overrides morphs the inherited version, replacing it public overrides sub refuel(byVal x as integer) console.writeline("pure renewable energy!") fuel = fuel + x end sub '###### end class
class limo inherits car public overrides sub setSpeed(byVal s as integer) if s > 100 then maxSpeed = 100 else maxSpeed = s end if end sub end class
class musclecar inherits car private leatherSeating as boolean public overrides sub drive() fuel = fuel - 30 console.writeline("vroom vroom!") end sub public sub setLeather(s as boolean) leatherSeating = s end sub public function getLeather() return leatherSeating end function end class
Polymorphism allows you to inherit attributes from a parent class, but redefine some of the methods or attributes