W3docs

Концепции ООП в Java

Обзор объектно-ориентированного программирования в Java: инкапсуляция, наследование, полиморфизм и абстракция.

Объектно-ориентированное программирование (ООП) — это способ организации кода вокруг объектов вашей программы, а не вокруг шагов. Вместо одного длинного скрипта, оперирующего сырыми переменными, вы описываете виды объектов в своей предметной области — User, Order, BankAccount — и наделяете каждый из них данными и поведением, которые ему нужны. Остальная часть программы обращается к этим объектам с запросами, не вмешиваясь в их внутреннее устройство.

Java создавалась именно вокруг этой идеи. Каждая строка кода на Java живёт внутри класса, а класс — это шаблон, из которого создаются объекты. До этого момента вы писали в основном процедурный код внутри main и нескольких статических вспомогательных методов; в этой части книги вы начнёте проектировать собственные классы.

Классы и объекты в одном предложении

Класс описывает вид объекта — какие данные он хранит и что умеет делать. Объект — это один конкретный экземпляр этого вида.

public class Dog {
  String name;
  int age;

  void bark() {
    System.out.println(name + " says woof");
  }
}

Dog d = new Dog();   // d is an object — one specific dog
d.name = "Rex";
d.bark();            // Rex says woof

Dog — это класс. d — это объект. Ключевое отличие от процедурного кода: объект объединяет состояние (поля name и age (fields)) и поведение (метод bark() (method)) в единое целое. Можно создать сколько угодно объектов Dog; каждый получит свою копию name и age и сможет независимо вызывать bark(). Подробно это рассматривается в главе классы и объекты.

Четыре столпа

ООП традиционно строится на четырёх концепциях. Каждой из них посвящена отдельная глава в этой части книги — здесь лишь краткий обзор, чтобы вы понимали, куда движетесь.

Инкапсуляция

Скрывайте данные объекта; открывайте поведение. Внешний код обращается с запросом account.deposit(50), а не напрямую изменяет account.balance += 50. Преимущество в том, что класс сам управляет своими инвариантами — никто снаружи не сможет привести его в недопустимое состояние.

public class Account {
  private int balance;                          // hidden

  public void deposit(int amount) {             // public behavior
    if (amount <= 0) throw new IllegalArgumentException();
    balance += amount;
  }
}

Подробнее — в главе инкапсуляция.

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

Класс может расширять другой, перенимая его поля и методы и добавляя к ним свои. Cat extends Animal повторно использует всё, что уже есть в Animal, и определяет лишь то, что специфично для кошек.

public class Animal {
  void breathe() { System.out.println("inhale, exhale"); }
}
public class Cat extends Animal {
  void purr()   { System.out.println("rrr"); }
}

Cat c = new Cat();
c.breathe();   // inherited
c.purr();      // own

Подробнее — в главе наследование.

Полиморфизм

Один и тот же вызов может вести себя по-разному в зависимости от того, какой объект его получает. Переменная типа Animal может указывать на Cat, Dog или Cow — вызов speak() на ней выбирает нужное поведение во время выполнения.

Animal a = new Cat();
a.speak();   // calls Cat's speak, even though a is typed as Animal

Подробнее — в главе полиморфизм.

Абстракция

Определяйте что делает объект, не фиксируя как. interface Shape говорит, что у каждой фигуры есть метод area(); каждая конкретная фигура — Circle, Square — предоставляет собственную формулу. Код, работающий с фигурами, не обязан знать, с каким именно их видом он имеет дело.

public interface Shape {
  double area();
}

Подробнее — в главе абстракция.

Четыре столпа в сводной таблице

СтолпИдея в одной строкеИнструмент Java
ИнкапсуляцияСкрыть данные, открыть поведениеполя private + публичные методы
НаследованиеПовторно использовать и расширять классextends
ПолиморфизмОдин вызов, поведение выбирается во время выполненияпереопределение + переменные супертипа
АбстракцияОпределить что, а не какинтерфейсы и абстрактные классы

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

Зачем это нужно?

Для скрипта в 20 строк ООП избыточно. Его преимущества проявляются по мере роста программы:

  • Локальное рассуждение. Класс BankAccount владеет своими правилами. Чтобы понять или изменить логику пополнения, достаточно прочитать метод deposit — нет нужды искать по всей кодовой базе вхождения balance +=.
  • Повторное использование без копирования. Наследование и композиция позволяют SavingsAccount строиться на основе Account, а не дублировать его.
  • Взаимозаменяемость. Функция, принимающая Shape, работает с любой фигурой, которая существует сегодня, и с любой, которую вы добавите завтра.
  • Тестируемость. Небольшие объекты с чёткими обязанностями легко создавать, использовать и проверять.

Java — далеко не единственный объектно-ориентированный язык: Python, C#, Kotlin, Ruby и многие другие разделяют те же идеи с разным синтаксисом. Всё, что вы изучите в этой части, применимо и там.

ООП — не единственная парадигма

Даже в Java вы уже писали код, который не является строго объектно-ориентированным: статические вспомогательные методы, примитивные вычисления, обычный управляющий поток. Современная Java совмещает парадигмы — функциональные конвейеры со стримами и лямбдами, неизменяемые данные с записями, декларативную работу с аннотациями. ООП — это хребет языка, а не клетка. Используйте класс, когда моделируете сущность с состоянием и поведением; прибегайте к статическому методу, когда просто нужно вычисление.

Пример с работающим кодом

Полный код из приведённых выше фрагментов, собранный вместе, чтобы вы могли его запустить:

java— editable, runs on the server

Что дальше

Теперь, когда вы знаете общую картину ООП, следующая глава разбирает его основы: как из определения класса получается объект в памяти, что именно делает new и чем ссылки на объекты отличаются от примитивов. Переходите к главе классы и объекты в Java.

Практика

Практика
Какое утверждение лучше всего описывает разницу между классом и объектом?
Какое утверждение лучше всего описывает разницу между классом и объектом?
Was this page helpful?