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
final
vsfinalize
vsfinally
- 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
Training002
and import it to eclipse - Change class
pl.edu.bogdan.training.exercises.encapsulation.Circle
to 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
Class2
putCar
and fill the diagram. Remember about exceptions. - For classes
pl.edu.bogdan.training.exercises.abstraction.Car
,pl.edu.bogdan.training.exercises.abstraction.Plane
andpl.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
go
method
- Create enumerator for keeping colours. Each colour has to have field with hexadecimal value
- Fix enum
pl.edu.bogdan.training.exercises.enumerator.Operation
that way, thecalc
method 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.Person
to keep its objects inHashSet
effectively - Download any book in txt format from WolneLektury and count frequency of each letter in this book (use
Map
collection) - 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
A
andB
that way object of classB
is 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.out
is object of classPrintStream
. ClassPrintStream
describes an abstraction of stream. ObjectSystem.out
is concrete stream - standard output stream of our application."Hello!"
is object of classString
. ClassString
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
hasList
ofStudents
and also every class is part of someSchool
- Every
Computer
has its ownProcessor
which is useless withoutComputer
andComputer
cannot exist withoutProcessor
- Every
Circle
isEllipse
but there areEllipse
which 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 Student
s. 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 obtain
Taxi. Every
Taxiobject can be understood as
Carobject. Inheritance let us avoid copying code of class
Carinto class
Taxi`. 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:
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
- Fix class
pl.edu.bogdan.training.solid.exercise1.ReportGenerator.ReportItem
to be correct with SOLID rules - Fix class
pl.edu.bogdan.training.solid.exercise2.PrinterDriver
to be correct with SOLID rules - Divide methods in
pl.edu.bogdan.training.solid.exercise3.Car
into more specialized interfaces. - Fix class
pl.edu.bogdan.training.solid.exercise4.DatabaseConnector
to be correct with SOLID rules - Prepare objected oriented software for ATM.