Unit D1-3: Object orientated programming

Old teaching notes

I am still in the process of migrating & updating my teaching material for this unit. D1, D2 & D3 should be complete now but D4 is not finished. In the interim, so as to faciliate revision by the current Year 13s, I have shared the teaching slides I used with you.

Open shared folder containing former teaching slides


Unit D1: OOP concepts

Historical perspective

So far, we have been using a procedural style of programming. That is, our programs have started at the top of a big long list of instructions and worked their way to the bottom where it finished. Along the way our code may have looped a few times, or jumped off to other functions, but it always returned to where it jumped from and kept working it’s way through the procedure list.

Object orientated programming is a different way of thinking about computer programming. It was developed in the 1970s by a research project funded by the US Department of Defence that examined ways to improve code re-usability and maintainability. The findings of the research project were:

The task force proposed to make software behave like hardware OBJECTs. Subsequently, DoD replaces over 450 computer languages, which were then used to build DoD systems, with an object-oriented language called Ada.

Object orientated programming, as the name suggests, is centred around… objects! But what does that mean? In our case, an object is anything that we may want to make a program about!

What are objects?

I am an object, you are an object, our classroom is an object, our laptops are objects. The easiest way to grasp the concept initially is to think of physical objects in our known universe (though OOP programming can and is just as easily used to describe “abstract” or “logical” objects not just physical ones).

Designing object orientated programming depends identifying four things:

Classes and objects

What is a class?

The class is the blueprint to the object. Think of the class as architectural drawings, and the objects as all the homes built from those drawings.

In OOP, the class is a classification system for the types or categories of our objects. Each object belongs to a class/type/category.

For example, you and I might belong to a class called People. Our classroom could belong to a class called Rooms, and our laptops could belong to a class called Computers. Each class will be defined to describe various attributes and behaviours that all the objects have that class have.

If we consider the People class, attributes or properties that an object belonging to People may have include:

Behaviours for People objects could include:

These are attributes and behaviours that all People objects have, but that objects of Rooms and Computers may not.

What are attributes and behaviours you can think of for the classes of Rooms and Computers?

Terminology gotcha

Beaware that depending on the documentation you read, some of the following terminology may be used interchangably. Some are more philosphically aligned with object orientated methods, where as others (such as variables and functions) are importing the procedural programming term for the OOP equivilant.

As with procedural programming, attributes have a data type associated with them. These may be the implicit types int, long, double, String, or they could be another class.

Instantiation

This process of actually “creating” an object based on its class definition is known as instantiation. It is instantiation that will allocate the memory required to a new object based off the class definition and will execute the code necessary at its construction or birth (more on that later). (as per previous analogy: the act of building the house from the drawings)

UML

This wouldn’t be Computer Science if we didn’t love a digram! UML, or the Unified Modelling Language, is a set of diagrams used to document programs. We will use the UML Class diagram to document classes, their attributes and methods, and their relationships to each other. In this course you are expected to be able to (a) interpret and (b) create UML Class diagrams in the exam setting.

A simple UML Class diagram for the Person class we previously discussed would look like this:

Essentially it is a three row box. The first row is the class name, the second is the list of attributes (properties, variables) and the third is the list of methods (behaviours, functions).

Your turn: Complete the UML diagrams for Room and Computer.

Relationships

Objects (and by extension their classes) are frequently related to each other. This relationship is also identified in the UML diagram. While there are others, there are three types of relationships the IB syllabus dictates you understand. They are:

Looking at the example of a car, here are the three types of relationship and how the links are depicted in UML.

Conceptual summary

At its heart, OOP methodology is about abstracting a problem into the objects within the problem. The idea is that each object becomes a self contained unit, with all it’s attributes and methods enclosed within.

It is thought that this makes data safer and manipulation of data more predictable.

Exercises

Let’s explore a few common scenarios and decompose them into likely classes of objects that are documentated through UML diagrams.

Unit D2: OOP features

There are three core principles of object orientated programming you must be familiar with: Inheritance, encapsulation, and polymorphism.

Inheritance

Inheritance is the idea that a new class can be based off an already existing class. In doing so, it can inherit the methods and attributes of the superclass without them having to be re-written. If you change the code within the superclass, that change will automatically flow through to any subclasses created based off it.

For example the Dept of Transport could have an automobile class which contains vehicle owner details, registration tag etc. They can also have a motorcycle class, car class, and truck class that inherit from automobile.

Some other examples:

Be aware that unlike humans, classes in OOP can only have one parent!

Encapsulation

Encapsulation:

Looking at the example of a power steering mechanism of a car. Power steering of a car is a complex system, which internally have lots of components tightly coupled together, they work synchronously to turn the car in the desired direction. It even controls the power delivered by the engine to the steering wheel. But to the external world there is only one interface is available and rest of the complexity is hidden. Moreover, the steering unit in itself is complete and independent. It does not affect the functioning of any other mechanism.

Encapsulated code should have following characteristics:

Put another way, the only way the attributes (variables) within an object should be read or modified is by the methods (functions) belonging to that particular object. Code external to the object should never attempt to access the data directly. In theory, the code outside the object shouldn’t care what the data inside the object is – it should be able to treat it as a black box and just trust that it looks after itself correctly.

Because of the principle of encapsulation, it is quite common to write some simple methods that are known as “getters and setters” whose purpose is basically to get and set object variables. This would be for those attributes that the object doesn’t really care if they are modified by others or not.

For example, if you have an attribute String email;, it’s getter and setter would be:

public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }

A more complete example would be:

class Person() {
   String name = "";
   String getName(){
      return name;
   }
   void setName(String name){
      this.name = name;
   }
}

Person genta = new Person();
Person fred = new Person();
genta.name = "Genta";            // Breaks encapsulation
genta.setName( "Genta" );        // Obeys encapsulation
println( genta.getName() );

Access modifiers

In Java, encapsulation can be enforced by use of access modifiers. They specify the accessibility of a class and its members with respective to other classes and members. In Java they are:

Visibility of the class is checked before the visibility of the variable defined inside that class. If the class is visible only then the variables defined inside that class will be visible. If the class is not visible then no variable will be accessible, even if it is set to public.

We’ll revisit the previous example but add the access modifiers.

public class Person() {
   private String name = "";
   public String getName(){
      return name;
   }
   public void setName(String name){
      this.name = name;
   }
}

Person genta = new Person();
Person fred = new Person();
genta.name = "Genta";            // Will throw a compiler error
genta.setName( "Genta" );        // Will compile ok
println( genta.getName() );

Polymorphism

Polymorphism is the concept that allows our object to have multiple implementations of the same behaviour depending on the data it receives. There are two types of polymorphism that can be used within Java OOP: Overloading, and Overriding

Polymorphism by overloading

Overloading means we will have two methods with the identical name, but expecting different input parameters. Which one is executed depends on the parameters that are provided at run time.

void driveForward() {
   speed = 60; // Use 60km/hr as a default
}

void driveForward(int speed) {
   this.speed = speed;
}

Above we have two methods both called driveForward(), what determines which one is executed depends on whether an integer is provided as a parameter or not.

Overloading polymorphism is a very handy tool as it means we don’t have to continually remember “what did I call that method for this circumstance?”. It comes in particularly useful when we are usually going to want our program to assume a default value, so we don’t want to have to manually specify it every time, but also allowing us the possibility to override the default – such as the above example with the speed of the vehicle.

Polymorphism by overriding

Overriding means a subclass is implementing a method of the same name as exists in the superclass.

In this case the subclass will override the method of the superclass. Just like the inherited constructors, the super keyword can be used to invoke the parent method.

public class Person {
    String name;
    Person(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
}

public class Royalty extends Person {
    Royalty(String name) {
        super(name);
    }
    public String getName() {   // Overriding the .getName() method in Person
        return "Your Royal Highness "+name;
    }
}

public class Demo {
    public static void main() {
        Person commoner = new Person("John");
        System.out.println( commoner.getName() );
        Royalty queen = new Royalty("Elizabeth");
        System.out.println( queen.getName() );   // Will run the overriden getName() method
   }
}

Advantages of OOP

Once you start programming in Java, you’ll quickly realise the importance of packages. Packages in Java are a mechanism to encapsulate a group of classes, interfaces and sub packages.

Packaging of classes is used as loading the entire suite of functionality would consume too many system resources, especially when many/most programs don’t need it. A programmer can therefore make their application more efficient by loading in the various subsets of functionality to suit their needs.

Packages are also a convenient way of grouping together classes we have written for reuse in other programs. You can easily package several classes together, and bundle them into a JAR file to share with others in their library of packages.

As a result, complex algorithms and processes do not have to be “re-invented” but shared and re-used.

Some added advantages of this modularity is

Object­ oriented programming is popular in big companies, because it suits the way they write software. At big companies, software tends to be written by large (and frequently changing) teams of mediocre programmers. OOP imposes a discipline on these programmers that prevents any one of them from doing too much damage. The price is that the resulting code is bloated with protocols and full of duplication. This is not too high a price for big companies, because their software is probably going to be bloated and full of duplication anyway.

Disadvantages of OOP

Where there are advantages, there are of course, disadvantages. It is also the case that some of the “advantages” are increasingly contentious so make up your own mind.

The most glaring disadvantages of OOP are:

Also the Java incarnation of OOP is known for being particularly verbose. You’ll particularly notice this whenever trying to deal with any I/O.

Unit D3: OOP programming

Terminology

Before we spend too much time programming OOP, are there any terms we need to discuss? You should be familiar with all of these:

Find all the above in this OOP terminology exercise PDF

Programmer considerations

Finally, before we start programming, here are some considerations for you when programming your projects:

How much do programmers have ethical & moral duties in their work? For instance, is it the programmers duty to ensure adequate testing of products to prevent the possibilities of commercial or other damage? What about acknowledging the work of other programmers? What is the Open Source movement, and ethically how important is it to contribute to it if you plan on taking advantage of open source code in your project?

OOP example code

package com.pbaumgarten.oop;

public class Circle {
   private static final double pi = 3.1415;
   private double radius;

   Circle(double radius) {
      this.radius = radius;
   }
   public double getCircumference() {
      return( 2 * pi * radius );
   }
   public double getArea() {
      return( pi * radius * radius );
   }
   public double getRadius() {
      return( radius );
   }
   public void setRadius(double radius) {
      this.radius = radius;
   }
   public static void main(String[] args) {
      Circle c = new Circle(20);
      System.out.println("=== CIRCLE ===");
      System.out.println("Radius: "+c.getRadius() );
      System.out.println("Area: "+c.getArea() );
      System.out.println("Circumference: "+c.getCircumference() );
   }
}

In the above example, where is the code…

To use inheritance with our Circle, we might create a Sphere class.

package com.pbaumgarten.oop;

public class Sphere extends Circle {
   Sphere(double radius) {
      super(radius);
   }
   public double getVolume() {
      return( (4.0 * pi * radius * radius * radius ) / 3.0 );
   }
   public double getArea() {
      return( 4 * pi * radius * radius );
   }
   public static void main(String[] args) {
      Circle c = new Circle(5);
      Sphere s = new Sphere(10);
      System.out.println("=== CIRCLE ===");
      System.out.println("Radius: "+c.getRadius() );
      System.out.println("Area: "+c.getArea() );
      System.out.println("Circumference: "+c.getCircumference() );
      System.out.println("=== SPHERE ===");
      System.out.println("Radius: "+s.getRadius() );
      System.out.println("Surface area: "+s.getArea() );
      System.out.println("Volume: "+s.getVolume() );
   }
}

Your turn!

Create a Cylinder class such that the following main() will execute as expected. Notice you need an overloaded constructor!

   public static void main(String[] args) {
      Circle c = new Circle(5);
      Sphere s = new Sphere(10);
      Cylinder cy1 = new Cylinder(c,10);
      Cylinder cy2 = new Cylinder(30,10);
      System.out.println("=== CIRCLE ===");
      System.out.println("Radius: "+c.getRadius() );
      System.out.println("Area: "+c.getArea() );
      System.out.println("Circumference: "+c.getCircumference() );
      System.out.println("=== SPHERE ===");
      System.out.println("Radius: "+s.getRadius() );
      System.out.println("Surface area: "+s.getArea() );
      System.out.println("Volume: "+s.getVolume() );
      System.out.println("=== CYLINDER 1 ===");
      System.out.println("Radius: "+cy1.getRadius() );
      System.out.println("Length: "+cy1.getLength() );
      System.out.println("Surface area: "+cy1.getArea() );
      System.out.println("Volume: "+cy1.getVolume() );
      System.out.println("=== CYLINDER 2 ===");
      System.out.println("Radius: "+cy2.getRadius() );
      System.out.println("Length: "+cy2.getLength() );
      System.out.println("Surface area: "+cy2.getArea() );
      System.out.println("Volume: "+cy2.getVolume() );
   }

Construct code

Work your way through my Book of Java programming notes. Then return here for some exercises that are similar to what you’ll face in the IB Paper 2 examination.