JavaRush /Java Blog /Random EN /OOP principles
Author
Milan Vucic
Репетитор по программированию at Codementor.io

OOP principles

Published in the Random EN group
Java is an object oriented language. This means that Java programs should be written using an object-oriented style. And this style is based on the use of objects and classes in the program.

Basic principles of OOP:

OOP principles - 1Let's try with the help of examples to understand what classes and objects are, as well as how to put into practice the basic principles of OOP: abstraction, inheritance, polymorphism and encapsulation.

What is an object?

The world we live in is made up of objects. If we look around, we will see that we are surrounded by houses, trees, cars, furniture, dishes, computers. All these items are objects, and each of them has a set of certain characteristics, behavior and purpose. We are used to objects, and we always use them for very specific purposes. For example, if we need to get to work, we use a car, if we want to eat, we use dishes, and if we need to relax, we need a comfortable sofa. A person is used to thinking objectively to solve problems in everyday life. This was one of the reasons for the use of objects in programming, and this approach to creating programs was called object-oriented. Let's take an example. Imagine that you have developed a new phone model and want to mass-produce it. As a phone designer, you know what it is for, how it will function, and what parts it will consist of (case, microphone, speaker, wires, buttons, etc.). In this case, only you know how to connect these parts. However, you do not plan to produce phones personally, for this you have a whole staff of employees. So that you don't have to explain each time how to connect the parts of the phone, and so that all phones turn out the same during production, you will need to make a drawing in the form of a description of the phone device before they are released. for this you have a whole staff of workers. So that you don't have to explain each time how to connect the parts of the phone, and so that all phones turn out the same during production, you will need to make a drawing in the form of a description of the phone device before they are released. for this you have a whole staff of workers. So that you don't have to explain each time how to connect the parts of the phone, and so that all phones turn out the same during production, you will need to make a drawing in the form of a description of the phone device before they are released.In OOP, such a description, drawing, diagram, or template is called a class, from which an object is created when a program is executed. A class is a description of an object that has not yet been created, as if a general template consisting of fields, methods and a constructor, and an object is an instance of a class created on the basis of this description.

OOP abstraction

Let's now think about how we can go from an object in the real world to an object in the program using the phone as an example. The history of this means of communication exceeds 100 years and the modern telephone, unlike its predecessor from the 19th century, is a much more complex device. When we use a phone, we do not think about its structure and the processes taking place inside it. We simply use the features provided by the developers of the phone - buttons or touch screen to select a number and make calls. One of the first phone interfaces was a crank that had to be rotated to make a call. Of course, this was not very convenient. Nevertheless, the handle performed its function properly. If you look at the most modern and the very first phone, you can immediately highlight the most important details, which are important both for the device of the late 19th century and for the ultra-modern smartphone. These are making a call (dialing) and receiving a call. In essence, this is what makes a phone a phone, and not something else. Now we have applied the principle in OOP - highlighting the most important characteristics and information about the object.This principle of OOP is called abstraction. Abstraction in OOP can also be defined as a way of representing elements of a task from the real world as objects in a program. Abstraction is always associated with the generalization of some information about the properties of objects or objects, so the main thing is to separate significant information from insignificant information in the context of the problem being solved. There may be several levels of abstraction. Let's try to apply the principle of abstraction to our phones. To begin with, let's highlight the most common types of phones from the very first to the present day. For example, they can be presented in the form of a diagram shown in Figure 1. OOP principles - 2Now, using abstraction, we can extract common information in this object hierarchy: a common abstract object type - a phone, a general characteristic of a phone - the year it was created, and a common interface - all phones are able to receive and send calls. Here's what it looks like in Java:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outputNumber);
    public abstract void ring (int inputNumber);
}
Based on this abstract class, we will be able to create new types of phones in the program using other basic Java OOP principles, which we will discuss below.

Encapsulation

With the help of abstraction, we highlight what is common to all objects. However, each phone model is individual and somewhat different from others. How can we draw boundaries in the program and designate this individuality? How to make sure that none of the users accidentally or intentionally could break our phone, or try to remake one model into another? For the world of real objects, the answer is obvious: you need to put all the details in the phone case. After all, if this is not done and all the insides of the phone and the wires connecting them are left outside, there will definitely be an inquisitive experimenter who wants to “improve” the operation of our phone. To exclude such interference in the design and operation of an object, OOP uses the principle of encapsulation- another basic principle of OOP, in which the attributes and behavior of an object are combined in one class, the internal implementation of the object is hidden from the user, and a public interface is provided to work with the object. The task of the programmer is to determine which attributes and methods will be available for public access, and which are the internal implementation of the object and should not be changed.

Encapsulation and access control

For example, during production, information about it is engraved on the back of the phone: the year of its release or the logo of the manufacturer's company. This information quite specifically characterizes this model - its state. We can say that the developer of the phone took care of the immutability of this information - it is unlikely that anyone would think of removing the engraving. In the Java world, the state of future objects is described in the class using fields, and their behavior is described using methods. The ability to change the state and behavior is carried out using the access modifiers to fields and methods - private, protected, public, and alsodefault(default access). For example, we decided that the year of creation, the name of the phone manufacturer, and one of the methods belong to the internal implementation of the class and cannot be changed by other objects in the program. With code, the class can be described like this:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    //findComutator
    //openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("I'm calling a number");
}

public void ring() {
    System.out.println("Дзынь-дзынь");
}

 }
The modifier privatemakes the fields and methods of the class available only within that class. This means that it is impossible to access privatethe fields from outside, and there is no way to call privatemethods. Hiding access to the method openConnectionalso leaves us free to change the internal implementation of this method, since this method is guaranteed not to be used by other objects and will not break their work. To work with our object, we leave open methods calland ringwith the help of the modifier public. Providing public methods for working with an object is also part of the encapsulation mechanism, since if you completely close access to an object, it will become useless.

Inheritance

Let's look again at the phone diagram. You can see that it is a hierarchy in which the model below has all the features of the models above in the branch, plus its own. For example, a smartphone that uses a cellular network to communicate (has the properties of a cell phone), is wireless and portable (has the properties of a wireless phone), and can receive and make calls (the properties of a phone). In this case, we can talk about the inheritance of object properties. In programming, inheritance is the use of existing classes to describe new ones. Consider an example of creating a smartphone class using inheritance. All cordless phones run on rechargeable batteries that have a certain lifespan in hours. Therefore, let's add this property to the wireless phones class:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
callCell phones inherit the properties of a wireless phone, we also added the implementation of the and methods to this class ring:
public class CellPhone extends WirelessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("Calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("A subscriber is calling you" + inputNumber);
    }
}
And, finally, the smartphone class, which, unlike classic cell phones, has a full-fledged operating system. You can add new programs supported by this operating system to your smartphone, thus expanding its functionality. With code, the class can be described like this:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program){
    System.out.println("Installing" + program + "For" + operationSystem);
}

}
As you can see, we created quite a bit of new code to describe the class Smartphone, but got a new class with new functionality. Using the principle of inheritance of OOP allows you to significantly reduce the amount of code, and therefore make it easier for the programmer. OOP principles - 3

Polymorphism

If we look at all phone models, then, despite the differences in the appearance and design of the models, we can distinguish some common behavior in them - they can all receive and make calls and have a fairly clear and simple set of control buttons. Applying one of the basic principles of OOP, abstraction in terms of programming, which is already known to us, we can say that the phone object has one common interface. Therefore, phone users can quite comfortably use different models using the same control buttons (mechanical or touch), without going into the technical details of the device. So, you constantly use a cell phone, and you can easily make a call from his landline counterpart. Principle in OOP,polymorphism . Let's imagine that we need to describe a user in the program who can use any phone models to call another user. Here's how to do it:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// here it is polymorphism - using the abstract type AbstractPhone phone in the code!
        phone.call(number);
    }
}
 }
Now we will describe various models of phones. One of the first phone models:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outputNumber) {
        System.out.println("Turn the Handle");
        System.out.println("Give me the phone number, sir");
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
Regular landline phone:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("I'm calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
And finally, a cool video phone:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outputNumber) {
        System.out.println("I connect a video channel for the subscriber" + outputNumber );
    }
    @Override
    public void ring(int inputNumber) {
        System.out.println("You have an incoming video call..." + inputNumber);
    }
  }
Let's create objects in the method main()and test the method callAnotherUser:
AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Andrey");
user.callAnotherUser(224466,firstPhone);
// Rotate the knob
// Tell me the number of the subscriber, sir
user.callAnotherUser(224466,phone);
//Call number 224466
user.callAnotherUser(224466,videoPhone);
//I connect the video channel for subscriber 224466
By calling the same method on the object user, we got different results. The choice of a specific implementation of a method callwithin a method callAnotherUserwas made dynamically based on the specific type of the object that called it during program execution. This is the main advantage of polymorphism - the choice of implementation during the execution of the program. In the phone class examples above, we used method overriding, a technique that changes the method implementation defined in the base class without changing the method signature. This is essentially a method replacement, and it is the new method defined in the subclass that is called when the program is executed. Usually, when overriding a method, an annotation is used@Override, which prompts the compiler to check the signatures of the overridden and overridden methods. As a result , in order for the style of your program to conform to the concept of OOP and the principles of OOP java, follow the following tips:
  • highlight the main characteristics of the object;
  • highlight common properties and behavior and use inheritance when creating objects;
  • use abstract types to describe objects;
  • try to always hide methods and fields related to the internal implementation of the class.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION