Java Object Oriented Programming - PawelBogdan/BecomeJavaHero GitHub Wiki
Table of contents
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
finalvsfinalizevsfinally- Kinds of exceptions
- Static vs non-static
- What is enumerator?
- Nested classes? For details you can check here
- Java Collections API Details
Exercises
- Pull project
Training002and import it to eclipse - Change class
pl.edu.bogdan.training.exercises.encapsulation.Circleto be encapsulated. Add exceptions where appropriate. - Make your class from point 2 implement interface
pl.edu.bogdan.training.exercises.interfaces.Figure. Remember about exceptions. - Make your class from point 3 be immutable. How to forbid to extend this class?
- You have the following inheritance hierarchy:
in place of Class2putCarand fill the diagram. Remember about exceptions. - For classes
pl.edu.bogdan.training.exercises.abstraction.Car,pl.edu.bogdan.training.exercises.abstraction.Planeandpl.edu.bogdan.training.exercises.abstraction.Plane:- Fix them (every rule mentioned before)
- 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
gomethod
- Create enumerator for keeping colours. Each colour has to have field with hexadecimal value
- Fix enum
pl.edu.bogdan.training.exercises.enumerator.Operationthat way, thecalcmethod returns appropriate value of mathematical operation. - Fix class
pl.edu.bogdan.training.exercises.sorting.Person, create list of persons and sort it lexicographically using anonymous class - Adapt class
pl.edu.bogdan.training.exercises.sorting.Personto keep its objects inHashSeteffectively - Download any book in txt format from WolneLektury and count frequency of each letter in this book (use
Mapcollection) - Create class which can have only one instance.
- Consider class keeping information about some events and time of those events. How do you implement them
- Implement classes
AandBthat way object of classBis able to access private field of object of classA - Fix the mistake in package
pl.edu.bogdan.training.exercises.inheritance.
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:
System.outis object of classPrintStream. ClassPrintStreamdescribes an abstraction of stream. ObjectSystem.outis concrete stream - standard output stream of our application."Hello!"is object of classString. ClassStringdescribes 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
ClasshasListofStudentsand also every class is part of someSchool - Every
Computerhas its ownProcessorwhich is useless withoutComputerandComputercannot exist withoutProcessor - Every
CircleisEllipsebut there areEllipsewhich is notCircle
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).
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).
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).
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
- Construct your examples of each relation
- 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
- There are following classes:
Sources
- Wikipedia - Association
- Ważniak - Asocjacja
- Wikipedia - Composition
- Ważniak - Agregacja
- Ważniak - Kompozycja
- Ważniak - Dziedziczenie
- Wikipedia - Inheritance
- Wikipedia - Agregacja
- Wikipedia - Asocjacja
- Wikipedia - Dziedziczenie
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:
- Content of report changes
- 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:
SerializableCloneableIterable<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
- Fix class
pl.edu.bogdan.training.solid.exercise1.ReportGenerator.ReportItemto be correct with SOLID rules - Fix class
pl.edu.bogdan.training.solid.exercise2.PrinterDriverto be correct with SOLID rules - Divide methods in
pl.edu.bogdan.training.solid.exercise3.Carinto more specialized interfaces. - Fix class
pl.edu.bogdan.training.solid.exercise4.DatabaseConnectorto be correct with SOLID rules - Prepare objected oriented software for ATM.