Рубрики
Без рубрики

Наследование и полиморфизм – [ООП и Java #2]

Резюмируя, разговор об абстракции влечет за собой разговор о концепции барьера. Мы воздерживаемся… С пометкой “информатика”, java, ооп.

Резюмировать

Разговор об абстракции влечет за собой разговор о понятии барьера. Мы абстрагируемся и инкапсулируем из-за этого барьера между двумя субъектами: клиентом и исполнителем.

Для того чтобы клиент позвонил исполнителю, этот исполнитель должен быть создан и надежен в первую очередь. Это означает, что код клиента зависит от кода разработчика. Кроме того, разработчик может скрывать информацию от клиента с помощью абстракции данных/функций, а также сокрытия упаковки/информации. Я думаю, что это неудивительно для нас. Мы все выступаем в качестве клиентов в нашей повседневной жизни. Мы используем электронные устройства, которые большую часть времени воспринимаются как ментальный черный ящик. Мы не знаем, что происходит за этими покровами. Но мы верим, что они надежны, и ценим тот факт, что нам просто нужно знать достаточно, чтобы ими пользоваться.

Наследование

Наследование – хорошо известная идея в объектно-ориентированном программировании. Он фокусируется на отношениях между двумя объектами, где один из объектов является другим объектом. Например, автомобиль – это транспортное средство. Следовательно, класс объектов car может наследоваться от класса объектов vehicle. Это не требование, а скорее принцип проектирования. По сути, принципы ООП направлены на достижение следующего:

Там, где аналогичные функции выполняются отдельными частями кода, как правило, полезно объединить их в одно целое, абстрагируя различные части. – Бенджамин К.Пирс

Давайте рассмотрим пример. Предположим, вы хотите иметь бумажный объект, описывающий размер и цвет листа бумаги.

class Paper{
    private int height;
    private int width;
    private String color;

    Paper(int height, int width, String color){
        this.height= height;
        this.width = width;
        this.color = color;
    }
}

Теперь, если вам нужна стандартная бумага для принтера по умолчанию (обычная бумага формата А4), есть три способа сделать это.

  • 1. Создайте метод, вызывающий конструктор бумаги с параметрами по умолчанию
Paper PrinterPaper(){
    return new Paper(297, 210, "white");
}
  • 2. Перегрузите конструктор класса Paper. Это означает, что, объявляя другой конструктор с сигнатурой метода, немного отличающейся от исходного конструктора, Java рассматривает его как другую функцию, и Java будет знать, какую из них вызывать на основе заданного параметра.
class Paper{
    private int height;
    private int width;
    private String color;

    // original
    Paper(int height, int width, String color){
        this.height= height;
        this.width = width;
        this.color = color;
    }
    // added, will be called if no parameters are given
    Paper(){
        this.height= 297;
        this.width = 210;
        this.color = "white"
    }
}
  • 3. Последний путь – через наследование. Поскольку бумага для принтера – это Бумага, мы можем расширить класс бумаги
class PrinterPaper extends Paper{
    PrinterPaper(){
        super(297,210,"white");
    }
}

Мы видим, что наследование – это всего лишь один из способов ведения дел. Обычно это работает, когда между объектами существует четкая связь “есть”. Сравнивая 3 способа создания бумаги для принтера, 3-й способ кажется относительно более коротким по размеру кода, а также помогает в организации кода.

  • Материалы, связанные с бумагой для принтера, могут быть выделены в отдельный класс бумаги для принтера (разделение задач).
  • Материалы, которые совместно используются между бумагой принтера и бумагой, можно использовать с ключевым словом “супер”, которое вызывает родительское свойство или методы.

Полиморфизм

Из многих форм

В Java и особенно в случае наследования мы хотели бы избежать дублирования кода для общих функций. Однако существует необходимость в модификации кода. Эта потребность часто присуща созданию нового класса. Если нет, то мы вообще не будем выделять ничего значимого.

В случае наследования, хотя мы указываем, что существует код, которым должны делиться родитель и потомок, в дочернем классе также будут два основных различия.

  • Дочерний класс должен выполнить то, что родительский класс никогда не выполнит. В этом случае мы пишем новые методы в дочернем классе.
  • Дочерний класс должен выполнять то, что также выполняет родительский класс, но с небольшим изменением. В этом случае мы используем переопределение метода.

Примечание : Если дочерний класс ничем не отличается от родительского класса, он автоматически наследует те же методы от родительского класса.

В Java есть два часто переопределяемых метода.

  • toString(): влияет на то, как объект выводится на экран, изменяется для отображения некоторых характеристик объекта при распечатке.
  • равно(): проверяет, совпадают ли два объекта на основе критериев, помимо того факта, что объекты являются точной копией. Некоторые замечания по методу равенства:
// using the Paper example
@override
public boolean equals(Object obj){
    if(this == obj){
        return true; // if exact same copy
    } else if (obj instanceof Paper){ 
    // if belongs to the same class
        Paper p = (Paper) obj; // IMPT! type-cast before you can use the 
                            // Paper class methods
        return this.height == p.height && this.width == p.width 
&& this.color.equals(p.color);
    } else { // not even of the same class
        return false;
    }
}

Метод toString прост для понимания. Вы просто форматируете строку для печати на основе некоторого свойства по вашему выбору. Это не обязательно должно быть динамичным. Он работает до тех пор, пока возвращает строку.

@override
 public String toString() {
    return this.color + " paper of size: " + this.height + " " + this.width;
}

Напоминаем, что сигнатура метода должна быть точно такой же, чтобы переопределить другой метод. Это означает, что если метод имеет заголовок

public boolean equals(Object obj){
//...
}

Вы должны использовать один и тот же заголовок. Таким образом, замена “(Object obj)” вашим собственным объектом класса не работает.

// Example of a wrong way to override
@override
public boolean equals(Paper p){
//...
}
//This is wrong

Обычно возвращаемый тип один и тот же, чтобы один метод переопределял другой метод. Однако существует приемлемый случай, когда возвращаемый тип более специфичен, чем родительский метод (а НЕ наоборот!). Это будет работать, потому что по принципу взаимозаменяемости подкласс должен соответствовать ожиданиям своего родительского класса во всех аспектах. Следовательно, возвращаемый более конкретный объект все равно будет работать с любым клиентским кодом, работающим с более общим объектом (родительским). Я подробно остановлюсь на этом в следующей статье.

Оригинал: “https://dev.to/tlylt/inheritance-and-polymorphism-oop-java-2-d8g”