Java Object Oriented Programming - PawelBogdan/BecomeJavaHero GitHub Wiki

Table of contents

  1. Introduction to classes
    1. Introduction
    2. Encapsulation
    3. Immutable object
    4. Inheritance
    5. Few fast questions
    6. Exercises
  2. Relations between classes
    1. Association
    2. Aggregation
    3. Composition
    4. Inheritance
    5. Exercises
    6. Sources
  3. SOLID
    1. Single responsibility principle
    2. Open/closed principle
    3. Liskov substitution principle
    4. Interface segregation principle
    5. Dependency inversion principle
    6. Exercises
    7. Sources

Introduction to classes

Introduction

Class is description of some abstraction of surrounding world. For example:

public class Car {
    private String color;
    private int mileage;
}

Object is concrete being satisfying this abstraction. For example:

Car mercedes = new Car("green", 100);
Car ferrari = new Car("red", 10);

Encapsulation

According to Wikipedia:

encapsulation is used to refer to one of two related but distinct notions, and sometimes to the combination thereof:
A language mechanism for restricting direct access to some of the object's components.
A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.

Immutable object

According to Wikipedia):

an immutable object (unchangeable object) is an object whose state cannot be modified after it is created

Inheritance

According to Wikipedia:

inheritance is when an object or class is based on another object (prototypal inheritance) or class (class-based inheritance), using the same implementation. Inheritance in most class-based object oriented languages is a mechanism in which one object acquires all the properties and behaviours of parent object.

Few fast questions

  1. final vs finalize vs finally
  2. Kinds of exceptions
  3. Static vs non-static
  4. What is enumerator?
  5. Nested classes? For details you can check here
  6. Java Collections API Details

Exercises

  1. Pull project Training002 and import it to eclipse
  2. Change class pl.edu.bogdan.training.exercises.encapsulation.Circle to be encapsulated. Add exceptions where appropriate.
  3. Make your class from point 2 implement interface pl.edu.bogdan.training.exercises.interfaces.Figure. Remember about exceptions.
  4. Make your class from point 3 be immutable. How to forbid to extend this class?
  5. You have the following inheritance hierarchy: Inheritance in place of Class2 put Car and fill the diagram. Remember about exceptions.
  6. For classes pl.edu.bogdan.training.exercises.abstraction.Car, pl.edu.bogdan.training.exercises.abstraction.Plane and pl.edu.bogdan.training.exercises.abstraction.Plane:
    1. Fix them (every rule mentioned before)
    2. Find some abstraction layer to reduce the amount of code and to be able to:
      • create table {new Car(), new Ship(), new Plane()}
      • iterate over this table and run go method
  7. Create enumerator for keeping colours. Each colour has to have field with hexadecimal value
  8. Fix enum pl.edu.bogdan.training.exercises.enumerator.Operation that way, the calc method returns appropriate value of mathematical operation.
  9. Fix class pl.edu.bogdan.training.exercises.sorting.Person, create list of persons and sort it lexicographically using anonymous class
  10. Adapt class pl.edu.bogdan.training.exercises.sorting.Person to keep its objects in HashSet effectively
  11. Download any book in txt format from WolneLektury and count frequency of each letter in this book (use Map collection)
  12. Create class which can have only one instance.
  13. Consider class keeping information about some events and time of those events. How do you implement them
  14. Implement classes A and B that way object of class B is able to access private field of object of class A
  15. Fix the mistake in package pl.edu.bogdan.training.exercises.inheritance.

Up Back

Relations between classes

When we create application in Java, we describe actions between objects. Let us consider the simplest application ever:

public class Hello {
    public static void main(String [] args) {
        System.out.println("Hello!");
    }
}

In this program are two objects:

  1. System.out is object of class PrintStream. Class PrintStream describes an abstraction of stream. Object System.out is concrete stream - standard output stream of our application.
  2. "Hello!" is object of class String. Class String describes an abstraction of set of characters understood as words and sentences. Object "Hello!" is concrete literal.

Those two objects interacts. We say object System.out to get object "Hello!" and send it to standard output stream with the sign of new line in the end.

We can also describe more complex relations. For example:

  • Every Class has List of Students and also every class is part of some School
  • Every Computer has its own Processor which is useless without Computer and Computer cannot exist without Processor
  • Every Circle is Ellipse but there are Ellipse which is not Circle

Those relations are catalogued and have special signs to mark them on UML diagrams.

Association

(...) association defines a relationship between classes of objects that allows one object instance to cause another to perform an action on its behalf. Source

Let us consider the following example. We have two classes:

public class Person {
	private String name;

	public Person(String name) {
		super();
		this.name = name;
	}
	
	public void travel(Car car, int distance) {
		car.go(distance);
	}
}

public class Car {
	private String color;
	private int mileage;
	
	public Car(String color, int mileage) {
		super();
		this.color = color;
		this.mileage = mileage;
	}
	
	public void go(int numberOfMiles) {
		mileage += numberOfMiles;
	}
}

Both classes can be found in package pl.edu.bogdan.training.association.example1 in project Training002 in my repository.

As we can see, objects of class Car and class Person can exist separately. According to definition: Car allows Person to perform an action on its behave. In other words, object of Person gets reference to object Car to perform one specified action only.

We mark an association on UML diagram as a plain line between class boxes. We can name the relation (for example Person uses Car), we can also add multiplicity of relation (i.e. one Person can uses many Cars and one Car can be used by many Persons).

Up Back

Aggregation

Aggregation is type of relation of objects when one object "consist of" other objects. Let us consider the following example. We have two classes:

public class Student {
	private String firstName;
	private String lastName;
	private int age;
	
	
	public Student(String firstName, String lastName, int age) {
		super();
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age;
	}	
}

public class Course {
	private String name;
	private Student[] students;
	private int amountOdStudents;
	
	public Course(String name, int size) {
		this.name = name;
		this.students = new Student[size];
		this.amountOdStudents = 0;
	}
	
	public void addStudent(Student s) {
		if (amountOdStudents + 1 < students.length) {
			students[amountOdStudents] = s;
			amountOdStudents++;
		}
	}
	
}

Both classes can be found in package pl.edu.bogdan.training.aggregation.example1 in project Training002 in my repository.

As we can see, we each Course has some Students. But objects of Student can exist without Course.

We mark an aggregation on UML diagram as a plain line between class boxes with a empty diamond near containing class box. We can name the relation (for example Course has Students), we can also add multiplicity of relation (i.e. one Student can attends many Courses but no more than 5 and one Course can have many Students but no more than 20).

Up Back

Composition

Composition is stronger relation than aggregation. In composition relation one object "consists of" other objects, but inside objects cannot exist without outside object. Let's consider the following example:

public class Course {
	private String name;
	
	public Course(String name) {
		this.name = name;
	}
}

public class School {
	private String name;
	private Course[] courses;
	
	public School(String name) {
		this.name = name;
		this.courses = new Course[4];
		this.courses[0] = new Course("Literature");
		this.courses[0] = new Course("Math");
		this.courses[0] = new Course("Biology");
		this.courses[0] = new Course("History");
	}
}

Both classes can be found in package pl.edu.bogdan.training.composition.example1 in project Training002 in my repository.

As we can see objects of Course will be destroyed when the object School is destroyed. This emphasises the difference between aggregation and composition.

We mark a composition on UML diagram as a plain line between class boxes with a filled diamond near containing class box. We can name the relation (for example School has Courses), we can also add multiplicity of relation (i.e. one School can can have many Courses but no more than 10 and one Course can be taught in only one School).

Up Back

Inheritance

Is relation named 'is. It means that we have base class and we extends this class with some properties and behaviour. Very common example is class Car. We can add property priceForMileand we obtainTaxi. Every Taxiobject can be understood asCarobject. Inheritance let us avoid copying code of classCarinto classTaxi`. You can see it in the following example:

public class Car {
	private String color;
	private int mileage;
	
	public Car(String color) {
		super();
		this.color = color;
		this.mileage = 0;
	}
	
	public void go(int numberOfMiles) {
		mileage += numberOfMiles;
	}
}

public class Taxi extends Car {
	
	private double priceForMile;
	
	public Taxi(double priceForMile) {
		super("yellow");
		this.priceForMile = priceForMile;
	}
	
	public double costOfCourse(int distance) {
		go(distance);
		return distance*priceForMile;
	}
}

Exercises

  1. Construct your examples of each relation
  2. Model using UML and Java code the following scenario:
    • There are following classes: School, Teacher, Student, Class
    • Teacher works in school and teaches class, every teacher can teach at most 5 classes
    • Student attends at most 10 classes
    • At most 25 student can attend specified class
    • School can have at most 20 classes and 50 teachers

Up Back

Sources

  1. Wikipedia - Association
  2. Ważniak - Asocjacja
  3. Wikipedia - Composition
  4. Ważniak - Agregacja
  5. Ważniak - Kompozycja
  6. Ważniak - Dziedziczenie
  7. Wikipedia - Inheritance
  8. Wikipedia - Agregacja
  9. Wikipedia - Asocjacja
  10. Wikipedia - Dziedziczenie

Up Back

SOLID

According to English Wikipedia:

SOLID is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible and maintainable. Source

Single responsibility principle

It is very simple rule: one class has to have only one responsibility. For example: class DatabaseConnection should be responsible for connection to database. It cannot be responsible for analysing content of database. Another example: class Car should describe property and behaviour of car and nothing more.

According to Wikipedia this rule is equivalent to statement:

A class should have only one reason to change.

What does it mean exactly. Let's consider the example from Wikipedia: we have class responsible for generating the reports. Imagine two situations:

  1. Content of report changes
  2. Format of report changes

If both of these situation are cause of changing the class, it means the class does not satisfy the single responsibility principle.

Open/closed principle

According to Wikipedia we can describe this rule in the following way:

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

Let's consider the class responsible for operating the printer of some producer. So the class should be closed, it means nobody can change this class. If somebody would change it, the printers would stop working. But the producer created new model of the printer with a new feature. There is no point in creating the whole new class responsible for this new model of the printer. We should be able to extends existing class by adding code for the new feature. It means that the class needs to be open.

In object oriented programming it means that, we should not change behaviour of released class. If we did so, the software dependent on our class would stop working. But everybody using our realised class should be able extends our class to use our code to their purposes.

Liskov substitution principle

Wikipedia explains this rule in detail. Let's see on example. We have class:

public class Car {
	public void go(int distance) {
		// some instructions
	}
}

And the class extending previous one:

public class Taxi extends Car {
	@Override
	public void go(int distance) {
		// some instructions
	}
}

Of course we can create objects in the following way:

Car c = new Car();
Taxi t = new Taxi();

This is obvious. The Liskov rule states that every object of class Taxi can be considered as object of class Car. So, we can create object in the following way:

Car t = new Taxi();

We can also execute the following instructions:

Taxi t = new Taxi();
Car c = (Car)t;

We can also execute the following function:

void f(Car car) {
}

for objects:

Car c = new Car();
Taxi t = new Taxi();
f(c);
f(t);

The Liskov rule demands to project the software in that way, that we should be able to use every Taxi object in the same way as we use Car object. It means that method go(int distance) in Taxi class cannot throw exception if the overridden method in Car object does not.

Interface segregation principle

According to Wikipedia

Many client-specific interfaces are better than one general-purpose interface.

It means that we should create interfaces that describes as narrow functionality as possible. It can be easily seen on ArrayList class from Java Collection library (see documentation of Java). ArrayList implements the following interfaces:

  • Serializable
  • Cloneable
  • Iterable<E>
  • Collection<E>
  • List<E>
  • RandomAccess

It means that ArrayList has method of many different interfaces. If developer wants to use ArrayList as List one cannot be aware of other methods of ArrayList because one does not need them. And because there are more classes implementing List interface, developer can choose the best suitable for one's needs.

Dependency inversion principle

According to Wikipedia the sense of this rule can be describe as follows:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.

Let's consider the example of web application displaying content of database. We have module responsible for displaying content of database and module responsible for obtaining data from user. Those two modules depends on the module responsible for reading and writing database. This module depends on module responsible for connection with database server.

Another example is List interface. If we use the interface, we want to be able to add elements to list and remove elements from the list. We do not want to know how those methods are implemented in detail.

When we project the software, we should think what it should do first and then how it should be implemented.

Exercises

  1. Fix class pl.edu.bogdan.training.solid.exercise1.ReportGenerator.ReportItem to be correct with SOLID rules
  2. Fix class pl.edu.bogdan.training.solid.exercise2.PrinterDriver to be correct with SOLID rules
  3. Divide methods in pl.edu.bogdan.training.solid.exercise3.Car into more specialized interfaces.
  4. Fix class pl.edu.bogdan.training.solid.exercise4.DatabaseConnector to be correct with SOLID rules
  5. Prepare objected oriented software for ATM.

Sources

  1. Polish Wiki - SOLID
  2. English Wiki - SOLID

Up Back