Object Oriented Concepts¶
Abstractions¶
Object-Oriented Programming (OOP) is an experiment in using the computer as an expressive medium to port our ideas into the machine. Like all languages, programming languages are abstractions - general tools that are designed to represent more specific models of real life concepts. Let's take a look into different programming languages sorted by least abstract (closest to the machine) and most abstract (closest to natural language).
In the world of computers an Assembly Language is the minimal abstraction of the communication between human and the computer, which is often described as low-level language. It can be directly translated into machine code, but it uses mnemonics to represent the instructions to make it easier to understand. In order to convert assembly language into machine code it needs to be translated using an assembler. This converts each statement into the specific machine code needed for the hardware on which it is being run. There is a one-to-one relationship between an assembly language instruction and its machine code equivalent. Each CPU has its own version of machine code and assembly language. Although assembly languages are easier to program with than machine code, it is still time-consuming and specialist work. It is mainly reserved for writing specific instructions for embedded systems such as washing machines or air-conditioning control systems.
Next step of evolution were imperative languages which are the sequences of statements designed to reach a certain goal, for example C language. They provided abstraction for an assembly language however they were so so specific that you weren't able to leave the realm of thinking in terms of the computer structure to focus on the problem itself. The product of that effort is the code that is hard to read and understand.
Imperative Programming
imperative programming is a
programming paradigm
that uses statements
that change a program's state.
You might want to read imperative vs functional language
Alternatively to computer-like models there are languages with the focus on problems you're trying to solve - Prolog for example - it uses chains of relations which can be checked by queries. They have one caveat though which is that if you step out the domain of the problems those languages are designed for, you will end up with pretty unwieldy code - for example Prolog's non-deterministic (definition: even for the same input algorithm, can exhibit different behaviors on different runs) evaluation strategy is problematic for deterministic computations.
Deterministic Computation
A deterministic model of computation, for example a deterministic Turing machine , is a model of computation such that the successive states of the machine and the operations to be performed are completely determined by the preceding state.
Non-deterministic Algorithm
a nondeterministic algorithm is an algorithm that, even for the same input, can exhibit different behaviors on different runs, as opposed to a [deterministic algorithm](https://en.wikipedia.org/wiki/Deterministic_algorithm "Deterministic algorithm".
The Object-Oriented Programming paradigm tries to overcome this issue by providing general tools for working with the problems, so instead thinking about the language you can focus on the work you're trying to do (to some extent).
Fundamental part of being able to grasp general concepts is the process of creating abstractions, in OOP we use abstract data types which are called classes. If you had the luck of learning about Aristotle, you can think about classes a bit like in his concept used for the classification of living things - for example: the abstract class of live bearing tetrapods can be represented by specific object like someone's cat named Oreo.
In OOP we create new definitions for the reality we are trying to map, and the new ways to represent data - we call them data types.
So, to be specific with definitions: a class is description for object's characteristics (data) and functionalities (behavior) which becomes interface of the communication.
If you're interested of what is a true OOP approach, we could look at what Alan Kay said about Small Talk (first influential OOP language):
Alan Kay definition of OOP by Small Talk¶
- Everything is an object. It works like special variable that stores data and you give request to achieve desired effect and change its state - like you press button to get soda from a vending machine, but you can map virtually anything to object representation.
- Objects can communicate by sending and receiving messages - working program is like multiple ports (objects) that send each other ships (data) through river streams (it could be inside program or in the network)
- Each object has its ow memory which consists of other objects. You can picture it as some kind of bento meal - the whole dish consists of many sub parts, but you take one package, so you just eat whole thing and don't think about complexity inside when you don't have to.
- Each object is an instance of a class. Class is representing general grouping like for example \(1 \in \mathbb{N}\) 1 is an instance (object) of an \(\mathbb{N}\) set.
- The class is the repository for behavior associated with an object. It means that all objects of the same class can perform the same action. For example mouse button and keyboard key are Buttons, so they both have Key Pressed functionality.
Interface of the Object¶
In real world many objects are of the same kind movies, games etc. A class (which is often called a type - a pet Captain Meows is a type of Cat) is an abstract data type for object: a blueprint - it describes functionalities by what kind of behaviors are possible so we can modify object characteristics - an interface. If we have specified class we can create as many objects as we can and the only constraints are resources of the computer.
1 2 |
|
Duck
has 2 functionalities in its interface: it can walk and quack (this is what ducks mostly
do). The interface describes what you can request from specific object, you send it (d1.quack()
)
and object performs action based upon it (specific duck performs its quacking code). Also a small
but important bit of terminology:
d1
is a reference for theDuck
object.- processing data in object is done via methods (
walk(distance)
is a method) and method is an object-oriented fuction
fuction vs method
A function is a piece of code that is called by name. It can be passed data to operate on (i.e.
the parameters) and can optionally return data (the return value). All data that is passed to a
function is explicitly passed.
A method is a piece of code that is called by a name that is associated with an object. In most
respects it is identical to a function except for two key differences:
1. A method is implicitly passed the object on which it was called
2. A method is able to operate on data that is contained within the class (remembering that an
object is an instance of a class - the class is the definition, the object is an instance of that
data).
To send a message you choose the object reference (d1
) place dot after it and write method name.
Objects As Service Providers¶
When you are designing on working with Object-Oriented Program you can look at objects as service
providers. In that way you are creating, importing (or pasting form stackoverflow) set of objects
that are providing services that solve your problem. Thinking in such way may help you improve *
cohesiveness* of your code, in other words your parts of program will fit together well, and you
won't have desire to put too many functionalities in a single object. For example when you are
designing a calculator, the object Button
should provide service for pressing it, not the
calculation itself. After that you can pair specific Button
press to perform a request
to Calculation
object that has multiply
method.
Treating objects as service providers brings benefits also for consumers of your program - if someone finds services of your object useful, they can be fitted to other programs more easily.
Hiding the implementation¶
As you have seen - we should consider other people using our programs - clients.
The goal of the client programmer is to collect a toolbox full of classes to use for rapid application development. Our job is to build a class that exposes only what’s necessary to the client programmer and hide everything else and keeps everything else hidden. It is useful, because we can change the hidden portion without worrying about the impact of breaking workflow of a client. Why? Because if it’s hidden, the client programmer which means the class creator can change the hidden portion at will without worrying about the impact on anyone else and it reduces the possibility of introducing new bugs, because client has less stuff to break. It is also beneficial for the client because if we hide code that is not used for problem-solving by them.
Java has 4 ways of setting access boundaries for a class:
- public - means the element is available to everyone
- private - means no one can access the element except you - inside methods of that type. Anyone trying to access a private member gets a compile-time error.
- protected - protected works like private, except of the inheriting class which can access protected members
- default - It is when you don't use any access modifier. It is sometimes called the package access because classes can access the members of other classes in the package, but outsite those look like private.
Reuse¶
There are two methods of reusing your code in Java:
- composition
- inheritance
Composition¶
If you think your class needs features of another class you can place object of that class inside.
It is called composition, because you compose a new class from existing classes.
The need for such design is when you ask yourself "does my class has a ...?"
(has-a relationship). For example Heart
is good candidate to be used in composition with
a Person
- Person
has a Heart
.
Diagram for such construction looks like that:
Clarification of the diagram
We should be more specific and use the composition link in cases where in addition to the part-of
relationship between Person
and Heart
- there’s a strong lifecycle dependency between the two,
meaning that when
Person
is deleted then Heart
is also deleted as a result. The composition link shows that a
class (container, whole) has exclusive ownership over other class/s (parts), meaning that the
container object and its parts constitute a parent-child/s relationship. If you are interested in
reading more about class diagrams you can check it
here
and diagrams in this article are built by
Mermaid library
(you should read that too).
Features of the Composition:
- it is flexible: - member objects of new class are private most of the time so changing them does not break client code.
- you can change your code at the runtime, so you don't have worry if your program won't compile ( good for extending features) and inheritance imposes compile-time restrictions.
Inheritance¶
Sometimes you might want to clone a class and add few features to it to extend it.
Inheritance is just that, but you don't have to rewrite unchanged part of the functionalities or if
you change the first class the class under it is changed too. The base class is called a
superclass or a parent and copy is called a subclass or a child. I prefer using
superclass and subclass terminology, because it is used extensively in the official documentation.
Here is diagram representation of inheritance.
Arrow should point to the base class.
General Features of The Inheritance¶
- Superclass should contain the core of functionalities shared amongst its subclasses.
- With the inheritance you don't need to create intermediate models to provide solution for a problem
- It represents is-a relationship: superclass has in possession all the members of the base class (however private elements are not available at clients disposition), so it duplicates all its features (and has possibility to add more functionalities), so subclass is always a type of superclass
The Ways of Implementing The Inheritance¶
You can implement inheritance in two ways:
-
Add new methods to a subclass.
You basically add new functionalities to the subclasses thus differentiate and make them more specific. This is the most common way of implementing inheritance.
-
Change behavior of existing classes.
It relies on the fact that the base class already has methods and you can change what they do. It is like telling the program "I have superclass method here, but I want it to perform something different". There is special term for this process called overriding. In the following example we are overridingdraw
anderase
method ofShape
class.classDiagram Shape <|-- Square Shape <|-- Circle class Shape { -int area +draw() void +erase() void } class Square { +draw() void +erase() void } class Circle { +draw() void +erase() void }We are drawing shapes in different ways:
circle.draw()
andtriangle.draw()
will perform task in specific way.
Inheriting from an existing type creates a new type. This new type contains not only all the members of the existing type (although the private ones are hidden away and inaccessible), but more importantly it duplicates the interface of the base class. That is, all messages accepted by base-class objects are also accepted by derived-class objects. We know the type of a class by the messages it accepts, so the derived class is the same type as the base class.
Understanding the concepts of the inheritance is not enough to write a good code while using it. There are several design principles that you should follow when implementing your solutions, you can read more about them here.
Warning
This is still work in progress and everything past following line will be changed / removed soon
Objects vs normal life¶
Real-world objects share two characteristics: They all have state and behavior. Dogs have state (name, color, breed, hungry) and behavior (barking, fetching, wagging tail).
Software objects are conceptually similar to real-world objects: they too consist of state and related behavior. An object stores its state in fields (variables in some programming languages) and exposes its behavior through methods (functions in some programming languages). Methods operate on an object's internal state and serve as the primary mechanism for object-to-object communication.
For example in object - bike attributing state (current speed, current pedal cadence, and current gear) and providing methods for changing that state, the object remains in control of how the outside world is allowed to use it.
!!! warning Hiding internal state and requiring all interaction to be performed through an object's methods is known as data encapsulation - a fundamental principle of object-oriented programming.
Benefits Of Object Oriented Programming¶
- Modularity
Source code for objects can be maintained independently of other objects source code (like parts for modular guns can make close combat rifle or sniper rifle)
- Information-hiding
By interacting only with an object's methods, the details of its internal implementation remain hidden from the outside world (like computer's keyboard keys - we provide plastic shell for touching and do not expose circuits which can be easily damaged)
- Code re-use
If an object already exists (perhaps written by another software developer), you can use that object in your program. This allows specialists to implement/test/debug complex, task-specific objects, which you can then trust to run in your own code (You can copy stuff from stackoverflow and it works, and you still have a job)
- Pluggability and debugging ease
If a particular object turns out to be problematic, you can simply remove it from your application and plug in a different object as its replacement. This is analogous to fixing mechanical problems in the real world.
What Is a Class?¶
In the real world, you'll often find many individual objects all the same kind. There may be thousands of other bicycles in existence, all the same make and model. Each bicycle was built from the same set of blueprints and therefore contains the same components. In object-oriented terms, we say that your bicycle is an instance of the class of objects known as bicycles. A class is the blueprint from which individual objects are created.
Let see class describing bicycle:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
And here is code that will create bicycle objects and change their state via methods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Output:
1 2 |
|
What Is Inheritance¶
Object-oriented programming allows classes to inherit commonly used state and behavior from other classes. In this example, Bicycle now becomes the superclass of MountainBike, RoadBike, and TandemBike. In the Java programming language, each class is allowed to have one direct superclass, and each superclass has the potential for an unlimited number of subclasses:
The syntax for creating a subclass is simple. At the beginning of your class declaration, use the extends keyword, followed by the name of the class to inherit from:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
What Is an Interface¶
As you've already learned, objects define their interaction with the outside world through the methods that they expose. Methods form the object's interface with the outside world; the buttons on the front of your television set, for example, are the interface between you and the electrical wiring on the other side of its plastic casing. You press the \"power\" button to turn the television on and off. In its most common form, an interface is a group of related methods with empty bodies. A bicycle's behavior, if specified as an interface, might appear as follows:
1 2 3 4 5 6 7 8 9 10 11 |
|
To implement this interface, you'd use the implements
keyword in the class declaration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Implementing an interface allows a class to become more formal about the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.
What Is a Package¶
A package is a namespace that organizes a set of related classes and interfaces. Conceptually you can think of packages as being similar to different folders on your computer. You might keep HTML pages in one folder, images in another, and scripts or applications in yet another. Because software written in the Java programming language can be composed of hundreds or thousands of individual classes, it makes sense to keep things organized by placing related classes and interfaces into packages. The Java platform provides an enormous class library (a set of packages) suitable for use in your own applications. This library is known as the \"Application Programming Interface\", or \"API\" for short. Its packages represent the tasks most commonly associated with general-purpose programming. For example, a String object contains state and behavior for character strings; a File object allows a programmer to easily create, delete, inspect, compare, or modify a file on the filesystem; a Socket object allows for the creation and use of network sockets; various GUI objects control buttons and check boxes and anything else related to graphical user interfaces. There are literally thousands of classes to choose from. This allows you, the programmer, to focus on the design of your particular application, rather than the infrastructure required to make it work.
Here is the view of packages that are created for this chapter:
Inspirations