Основные принципы ооп в java
Содержание:
Принцип подстановки Барбары Лисков (LSP)
Соответствует букве L акронима SOLID. Согласно этому принципу подтипы должны быть заменяемыми для супертипа. Другими словами, методы или функции, работающие с суперклассом, должны иметь возможность без проблем работать также и с его подклассами.
EPAM Data Quality Hiring Weeks
12–25 апреля, Онлайн, Беcплатно
tproger.ru
События и курсы на tproger.ru
LSP тесно связан с принципом единственной ответственности и принципом разделения интерфейса.
Если класс реализует больше функциональности, чем подкласс, то последний может не поддерживать некоторые функции и тем самым нарушает данный принцип.
Ниже приведён пример такого кода на Java:
Функция провоцирует неявную ошибку при работе с экземпляром класса , потому что позволяет устанавливать отличные друг от друга значения ширины и высоты. Согласно принципу LSP, функции, использующие ссылки на базовые классы, должны иметь возможность использовать объекты производных классов, не зная об этом. Поэтому для корректной работы функция должна проверять, является ли передаваемый объект экземпляром класса Square, и в этом случае не позволять установить разные значения ширины и высоты. Отсюда идёт нарушение принципа.
Курс по теме SOLID Principles of Object-Oriented Design.
Аналогия
Можно представить объекты отделами компании. В большинстве организаций сотрудники не работают один день с кадрами, на следующий начисляя зарплату, а затем неделю занимаясь розничной торговлей. У каждого отдела есть свой персонал с четко возложенными на него обязанностями. Есть и собственные данные: показатели заработной платы, продаж, учет сотрудников и т. д. Люди в отделах работают со своей информацией. Разделение компании, таким образом, облегчает контроль за ее деятельностью и поддерживает целостность данных. Бухгалтерия отвечает за платежные ведомости. Если необходимо знать общую сумму заработной платы, выплачиваемой в южном филиале в июле, не нужно рыться в архиве. Достаточно направить записку ответственному лицу, подождать, пока этот человек получит доступ к данным и отправит ответ с требуемой информацией. Это гарантирует соответствие регламенту и отсутствие постороннего вмешательства. Таким же образом объект в ООП обеспечивает организацию приложения.
Следует помнить, что ориентация на объекты не касается подробностей работы программы. Большинство инструкций C++ соответствует операторам процедурных языков, таких как С. Действительно, функции-члены в C++ очень похожи на функции в С. Только более широкий контекст позволит установить, является ли инструкция процедурной или объектно-ориентированной.
3 Что учить дальше?
Мы разобрали ценности и знаем к чему стоит стремиться, кроме того, мы поверхностно посмотрели на механизмы, которые предоставляет нам объектно-ориентированное программирование, не фокусируясь на каком-либо определенном языке
Однако, в программировании важна практика — посмотрите как описанные механизмы реализуются в вашем любимом языке и попробуйте реализовать небольшой проект.
Прочитайте про SOLID — постарайтесь заметить не только принципы, но также — проблемы и подходы к их решению.
Обратите внимание на модульное тестирование и TDD — это будет особенно полезно, если у вас не получается удачная архитектура. По моим наблюдениям, даже начинающий программист начинает писать более качественный код, если сначала подумает о том, как он этим кодом хочет пользоваться
Изучите библиотеку модульного тестирования вашего языка программирования и попробуйте писать тесты.
Посмотрите литературу о шаблонах проектирования , при этом я рекомендую не пытаться запомнить детали реализации паттернов, а ответить на вопросы «где я могу применить этот шаблон?», «какую пользу и вред я с этого получу?». Если это кажется вам тяжелым — посмотрите как с помощью паттернов можно улучшить качество кода .
3.1 Список использованных источников
- Рейтинг популярности языков программирования TIOBE. URL: https://tiobe.com/tiobe-index/
- SOLID принципы. Рефакторинг. URL: https://pro-prof.com/archives/1914
- Почему мне кажется, что студентов учат ООП неправильно. URL: https://habr.com/ru/post/345658/
- C++ Russia 2018: Фёдор Короткий, Память – идеальная абстракция. URL: https://vk.com/wall-105242702_701
- Мейер Б. Объектно-ориентированное конструирование программных систем. М.: Издательско-торговый дом «Русская Редакция», «Интернет-университет информационных технологий», 2005. 1232 с.: ил.
- Мартин Р. Чистый код. Создание, анализ и рефакторинг. Библиотека программиста. – СПб.: Питер, 2014. – 464 с.
- Джейсон Мак-Колм Смит Элементарные шаблоны проектирования : Пер. с англ. — М. : ООО “И.Д. Вильямс”, 2013. — 304 с.
- Диаграммы классов UML. URL: https://pro-prof.com/archives/3212
- Юнит-тестирование. Пример. Boost Unit Test. URL: https://pro-prof.com/archives/1549
- Э. Гамма Приемы объектно-ориентированного проектирования. Паттерны проектирования / Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес. – СПб.: Питер, 2009. – 366 с.
Абстракция
В рунете народ до сих пор спорит над определением абстракции в ООП. И проблема даже не в том, что все неправы, а в том, что все правы. Чем программа меньше, тем сильнее абстракция привязана к языку Java, чем больше, тем сильнее привязана к моделированию/упрощению объектов реального мира.
Но вроде бы лучшие умы сошлись на том, что:
Абстракция — это использование только тех характеристик объекта, которые с достаточной точностью представляют его в программе. Основная идея состоит в том, чтобы представить объект минимальным набором полей и методов и при этом с достаточной точностью для решаемой задачи.
В языке программирования Java абстракция осуществляется через использование абстрактных классов и интерфейсов.
Абстракция в реальной жизни
Хороший пример абстракции в реальной жизни — описание должностей в компании или организации. Название должности — это одно, а обязанности каждой конкретной должности — это уже совсем другое.
Представьте, что вы проектируете структуру своей будущей компании. Вы можете разделить обязанности секретаря: «разбросать» их по нескольким другим должностям. Можете разбить должность исполнительного директора на несколько независимых должностей: финансовый директор, технический директор, директор по маркетингу, директор по персоналу. Или, например, объединить должности офис-менеджера и рекрутера в одну.
Вы придумываете названия должностей в своей фирме, а потом «расбрасываете» обязанности по этим должностям. Абстракция – отвлечение от целостности объекта и выделение его главных свойств и составляющих, нужных нам.
С точки зрения же программирования, абстракция — это, скажем так, правильное разделение программы на объекты. Обычно любую большую программу можно десятками способов представить в виде взаимодействующих объектов. Абстракция позволяет отобрать главные характеристики и опустить второстепенные.
Классовое наследование
В классовом ООП классы являются чертежами для объектов. Объекты (или экземпляры) создаются на основе классов. Существует конструктор, который используется для создания экземпляра класса с заданными свойствами.
Например:
Здесь при помощи ключевого слова из ES6 мы создаём класс со свойствами и , которые хранятся в . Значения свойств задаются в конструкторе, а доступ к ним осуществляется в методе .
Мы создаём экземпляр класса с именем с помощью ключевого слова :
Объекты, созданные с помощью ключевого слова , изменяемы. Другими словами, изменения в классе повлияют на все объекты, являющиеся экземплярами этого класса, а также на дочерние классы, которые его расширяют ().
Для расширения класса мы можем создать другой класс. Расширим класс с помощью класса . — это с почтой и паролем:
Всё вроде бы хорошо работает, но использование классового подхода к наследованию привело к большому конструктивному недостатку: откуда пользователи класса (например, ) могут знать, что у этого класса есть свойства и и функция ? Одного взгляда на код класса недостаточно для того, чтобы сказать что-либо о его родительском классе. В итоге приходится копаться в документации или искать нужный код по всей иерархии классов.
Как говорит Дэн Абрамов:
Классовое наследование построено на создании связей через зависимости. На основе базовых классов (или суперклассов) создаются производные классы. Классовое наследование хорошо подходит для небольших и простых приложений, которые редко меняются и у которых не более одного уровня наследования (неглубокие деревья наследования позволяют избежать проблемы хрупкого базового класса) или совершенно разные сценарии использования. Однако по мере расширения иерархии такое наследование со временем будет невозможно поддерживать.
Эрик Эллиот описал, как классовое наследование может потенциально привести к провалу проекта, а в худшем случае — к провалу компании:
Когда много производных классов с очень разными функциями наследуются от одного базового класса, любое, казалось бы, безобидное изменение в базовом классе может привести к сбою в работе производных. За счёт усложнения кода и всего процесса создания продукта вы могли бы смягчить побочные эффекты, создав контейнер для инъекций зависимостей. Это обеспечило бы единый интерфейс для создания сервисов, потому что позволило бы абстрагироваться от подробностей создания. Есть ли способ получше?
Полиморфизм
Полиморфизм означает «иметь много форм», что, честно говоря, не очень помогает в определении. Мне нравится формулировать это так: используется один и тот же метод, только по-разному. Есть два способа реализации полиморфизма:
Перегрузка: имя метода остается неизменным, но параметры, возвращаемый тип и количество параметров могут изменяться:
// ПЕРЕГРУЗКА // Класс Animal реализует 3 метода конструктора, которые перегружаются. // Это означает, что мы можем создать новое животное тремя разными способами. class Animal { private String name; private int age; Animal() { name = "Fred"; age = 12; } Animal(String nm) { name = nm; age = 5; } Animal(String nm, int newAge) { name = nm; age = newAge; } }
Перегрузка в основах ООП – это когда метод подкласса имеет то же имя, параметры и возвращаемый тип, что и метод в суперклассе, но реализуется по-другому:
// СУПЕРКЛАСС class Animal { public void identify() { System.out.println("I am an animal!"); } } // ПОДКЛАСС class Dog extends Animal { public void bark() { System.out.println("Bark!"); } public void identify() { System.out.println("I am a dog!"); } } class Cat extends Animal { public void meow() { System.out.println("Meow!"); } public void identify() { System.out.println("I am a cat!"); } } class Bird extends Animal { public void chirp() { System.out.println("Chirp!"); } public void identify() { System.out.println("I am a bird!"); } }
Несколько правил переопределения метода в основах ООП Java:
- Методы подкласса должны иметь одинаковый возвращаемый тип и аргументы;
- Уровень доступа метода подкласса не может быть более низким, чем у метода суперкласса;
- Метод, объявленный завершенным или статическим, нельзя переопределить;
- Если метод не может быть унаследован, его нельзя переопределить.
Абстракция в ООП на Java
Абстракция – в основах ООП для начинающих это процесс скрытия всего, кроме релевантной информации об объекте. Например, нам не нужно знать, как работают часы, чтобы использовать их для определения времени. Абстракция позволяет сосредоточиться на том, что делает объект, а не на том, как он это делает:
// ОСНОВНАЯ АБСТРАКЦИЯ
// Мы можем использовать System.out.println(«Hello»), чтобы вывести строку на
// консоль и не заботиться о том, как работает метод println.
// АБСТРАКТНЫЕ КЛАССЫ
// Абстрактные классы содержат только объявление метода. Их назначение —
// выполнять роль суперклассов для других классов. Они не определяют, как
// методы реализуются, а только что они реализуют. Абстрактные классы не могут
// быть установлены, и подклассы ДОЛЖНЫ реализовать абстрактные методы.
abstract class FlyingAnimal {
public abstract void Fly();
}
class Bird extends FlyingAnimal {
protected String name;
protected int age;
Bird(String nm, int newAge) {
name = nm;
age = newAge;
}
@Override
public void Fly() {
System.out.println(«Flaps wings majestically.»);
}
}
// ИНТЕРФЕЙС
// Классы могут наследоваться только от одного суперкласса, но они могут
// реализовать несколько интерфейсов. Это расширяет возможности для применения
// абстракции. Классы, которые реализуют интерфейс, ДОЛЖНЫ реализовать
// методы в интерфейсе.
// Стандартные классы
class Animal {
private String name;
private int age;
public void identify() {
System.out.println(«I am an animal!»);
}
public void rename(String newName) {
name = newName;
}
public String getName() {
return name;
}
public void setAge(int newAge) {
if(newAge > 0)
age = newAge;
}
public int getAge() {
return age;
}
}
// Интерфейс для животных, которые могут летать. Нам нет дела до того,
// как они летают, просто они могут летать.
public interface ICanFly {
void Fly();
}
// Интерфейс для животных, которые могут плавать. Нам нет дела до того,
// как они плавают, просто они могут плавать.
public interface ICanSwim {
void Swim();
}
// Утка — это животное, которое может и летать, и плавать.
class Duck extends Animal implements ICanFly, ICanSwim {
public void Quack() {
System.out.println(«QUACK!»);
}
@Override
public void Identify() {
System.out.println(«I am a duck!»);
}
@Override
public void Fly() {
System.out.println(«Flaps wings majestically.»);
}
@Override
public void Swim() {
System.out.println(«Kicks feet.»);
}
}
// Рыба — это животное, которое умеет плавать
Обратите внимание на то, что
// реализация метода Swim отличается для утки и для рыбы.
class Fish extends Animal implements ICanSwim {
@Override
public void Identify() {
System.out.println(«I am a fish!»);
}
@Override
public void Swim() {
System.out.println(«Wiggles fish-body»);
}
}
// Самолет — это не животное, но он все равно может летать.
class AirPlane implements ICanFly {
protected String name;
protected int mileage;
@Override
public void Fly() {
System.out.println(«Turns propeller»);
}
}
Данная публикация является переводом статьи «Four Principles of Object-Oriented Programming with Examples in Java» , подготовленная редакцией проекта.
DRY (Don’t Repeat Yourself)
Переводится как «не повторяйся» и буквально означает, что нужно уходить от дублирующего кода и по возможности использовать абстракцию для общих вещей.
Если есть одинаковый блок кода в более чем двух местах, вынесите его в отдельный метод. Если вы используете жёстко запрограммированное значение более одного раза, сделайте его общедоступной константой. Преимущество этого принципа заключается в упрощении поддержки вашего кода.
Но важно не злоупотреблять этим принципом. Например, один и тот же код не подойдёт для проверки OrderId и SSN
Их форматы могут не совпадать, и на выходе функция выдаст некорректный результат. В качестве решения можно предусмотреть в методе проверку форматов для подобных наборов чисел.
Курс по теме Basics of Software Architecture & Design Patterns для Java на Udemy.
Объект в ООП: определение
При рассмотрении задачи программирования на ОО-языке вместо вопросов о ее разделении на отдельные функции возникает проблема разделения на объекты. ООП-мышление намного облегчает разработку приложений. Это происходит в результате сходства программных и реальных объектов.
Какие вещи становятся объектами в ООП? Ниже представлены типичные категории.
Физический объект в ООП – это:
- транспорт в моделях движения потока;
- электрические элементы в программах схемотехники;
- страны в модели экономики;
- самолет в системе управления воздушным движением.
Элементы среды компьютера пользователя:
- меню;
- окна;
- графика (линия, прямоугольник, круг);
- клавиатура, мышь, принтер, дисковые накопители.
Люди:
- работники;
- студенты;
- клиенты;
- продавцы.
Данные:
- книга учета;
- личное дело;
- словарь;
- таблица широт и долгот населенных пунктов.
Связь объектов реального мира и ООП стало результатом сочетания функций и данных: они произвели переворот в программировании. Такого близкого соответствия в процедурных языках нет.
Понятие «объект» в ООП
Сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса (например, после запуска результатов компиляции и связывания исходного кода на выполнение).
Объект — это появляющийся при создании экземпляра класса набор свойств и их значений в памяти, на которые можно сослаться с помощью идентификатора:
- каждое свойство состоит из имени и значения, ассоциированного с этим именем;
- значением свойства может быть функция, которую можно назвать методом объекта.
Свойства объекта в JavaScript
В JavaScript объект имеет свойства, ассоциированные с ним. Свойство объекта:
- можно понимать как переменную, закрепленную за объектом;
- определяют характеристики объекта.
Получение доступа к свойству объекта:
JavaScript
objectName.propertyName
// или
objectName
1 |
objectName.propertyName // или objectName»propertyName» |
Примеры:
JavaScript
var myCar = new Object(); // создание объекта с помощью конструктора
myCar.make = «Ford»;
myCar.model = «Mustang»;
myCar.year = 1969;
// или
myCar = «Ford»;
myCar = «Mustang»;
myCar = 1969;
1 |
varmyCar=newObject();// создание объекта с помощью конструктора myCar.make=»Ford»; myCar.model=»Mustang»; myCar.year=1969; myCar»make»=»Ford»; myCar»model»=»Mustang»; myCar»year»=1969; |
Имена свойств объекта могут быть строками JavaScript, или тем, что может быть сконвертировано в строку, включая пустую строку. Как бы то ни было, доступ к любому имени свойства, которое содержит невалидный JavaScript идентификатор (например, имя свойства содержит в себе пробел и тире или начинается с цифры), может быть получен с использованием квадратных скобок. Этот способ записи также полезен, когда имена свойств должны быть динамически определены (когда имя свойства не определено до момента исполнения).
Примеры
JavaScript
var myObj = new Object(),
str = «myString»,
rand = Math.random(),
obj = new Object();
myObj.type = «Dot syntax»;
myObj = «String with space»;
myObj = «String value»;
myObj = «Random Number»;
myObj = «Object»;
myObj = «Even an empty string»;
console.log(myObj);
1 |
varmyObj=newObject(), str=»myString», rand=Math.random(), obj=newObject(); myObj.type=»Dot syntax»; myObj»date created»=»String with space»; myObjstr=»String value»; myObjrand=»Random Number»; myObjobj=»Object»; myObj»»=»Even an empty string»; console.log(myObj); |
Обратите внимание, что все ключи с квадратными скобками преобразуются в тип String, поскольку объекты в JavaScript могут иметь в качестве ключа только тип String. Например, в приведенном выше коде, когда ключ obj добавляется в myObj, JavaScript вызывает метод obj.toString () и использует эту результирующую строку в качестве нового ключа
Роль полиморфизма
Последний принцип ООП — полиморфизм. Он обозначает способность языка трактовать связанные объекты в сходной манере. В частности, этот принцип ООП позволяет базовому классу определять набор членов (формально называемый полиморфным
интерфейсом), которые доступны всем наследникам. Полиморфный интерфейс класса
конструируется с использованием любого количества виртуальных или абстрактных членов.
По сути, виртуальный член — это член базового класса, определяющий реализацию
по умолчанию, которая может быть изменена (или, говоря более формально, переопределена) в производном классе. В отличие от него, абстрактный метод — это член
базового класса, который не предусматривает реализации по умолчанию, а предлагает только сигнатуру. Когда класс наследуется от базового класса, определяющего абстрактный метод, этот метод обязательно должен быть переопределен в производном
классе. В любом случае, когда производные классы переопределяют члены, определенные в базовом классе, они по существу переопределяют свою реакцию на один и тот же
запрос.
Рассмотрим для примера стек, т.е. область памяти, функционирующую по принципу «последним
пришел — первым обслужен». Допустим, что в программе требуются три разных типа
стеков: один — для целых значений, другой — для значений с плавающей точкой, третий — для символьных значений. В данном примере алгоритм, реализующий все эти
стеки, остается неизменным, несмотря на то, что в них сохраняются разнотипные данные. В языке, не являющемся объектно-ориентированным, для этой цели пришлось бы
создать три разных набора стековых подпрограмм с разными именами. Но благодаря
полиморфизму для реализации всех трех типов стеков в C# достаточно создать лишь один общий набор подпрограмм. Зная, как пользоваться одним стеком, вы сумеете
воспользоваться и остальными.
В более общем смысле понятие полиморфизма нередко выражается следующим
образом: «один интерфейс — множество методов». Это означает, что для группы взаимосвязанных действий можно разработать общий интерфейс. Полиморфизм помогает
упростить программу, позволяя использовать один и тот же интерфейс для описания
общего класса действий. Выбрать конкретное действие (т.е. метод) в каждом отдельном
случае — это задача компилятора. Программисту не нужно делать это самому. Ему достаточно запомнить и правильно использовать общий интерфейс.
Абстракция
Тут всё предельно просто. При абстракции выделяются главные и наиболее значимые характеристики предмета, одновременно с этим отбрасываются второстепенные и незначительные.
Простой пример: представьте, что мы создаём картотеку сотрудников компании. Естественно, мы вносим их основные характеристики: дату рождения, ИНН, ФИО, номер социального страхования. Разумеется, нас не интересуют ни рост, ни цвет глаз, ни длина волос. То есть мы абстрагируемся от ненужной информации.
А что если нужно создать картотеку модельного агентства? Согласитесь, что здесь ситуация кардинально меняется и вряд ли нам понадобится индивидуальный номер налогоплательщика, а вот данные о внешности будут очень кстати.
Принципы ООП
Главные принципы в ООП – абстрагирование, инкапсуляция, наследование и полиморфизм.
Абстрагирование (абстракция) – это выделение и представление существенных отличительных признаков, свойств, характеристик в терминах программирования.
Инкапсуляция – это «размещение в оболочке, капсуле», механизм объединения данных в единый компонент, дающий возможность защитить и спрятать их. То есть ограничить доступ одних компонентов программы к другим. Инкапсуляция позволяет над каждой частью программы работать изолированно. Это такая мантия-невидимка Гарри Поттера.
Наследование – это как в биологии схожесть детей, родителей и предков: передача свойств от одного объекта или класса другому, имеющему, помимо того, и собственные свойства. Похоже на смартфоны нового поколения: могут добавить камеры получше, но в целом наследуется то, чем мы уже пользуемся. Есть родительские/базовые классы и классы-потомки/наследники.
Полиморфизм: одно имя метода для класса – много внешне схожих, но технических различных действий, соответствующих особенностям наследников. Лаконичное определение: один интерфейс – множество реализаций.
В чем суть ООП?
В описании вакансий девелоперов часто можно увидеть требование «понимание ООП». А в описании языков программирования – «объектно-ориентированный язык программирования».
Парадигма ОПП лежит в основе многих мейнстримовых языков. ОО-языки: C++, С#, Java, JavaScript, Objective-C, Python, PHP, Perl, Ruby, Scala, Swift и др. То есть топовые языки, ряд языков общего назначения, языки для Android-, веб- и iOS-разработки. Популярные современные языки – мультипарадигмальные, по принципам ООП можно писать и на языках с другими парадигмами.
ООП как стиль написания программ подразумевает построение структуры, состоящей из взаимодействующих объектов. В рамках ООП нужно мыслить объектами. Объекты расположены в иерархии, самостоятельны и как-то взаимодействуют. Программа состоит из модулей – блоков, которые решают какие-то задачи. Изменения в этих участках могут не отражаться на других участках.
Определение звучит так. Объектно-ориентированное программирование – это методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
Инкапсуляция в Java
Инкапсуляция — принцип, согласно которому атрибуты объекта заключаются в этот объект. Это задает для атрибутов контекст. Это также позволяет программисту ограничить доступ к атрибутам, чтобы они изменялись и использовались только через методы, которые программист собирается применять:
// Эта переменная не инкапсулирована. // Поэтому в ней отсутствует какой-то контекст. String name; // БАЗОВАЯ ИНКАПСУЛЯЦИЯ // Эти переменные и методы инкапсулированы в классе Dog. Они являются его членами. class Dog { String name; int age; void bark() { System.out.println("Bark!"); } void rename(String newName) { name = newName; } } // МОДИФИКАТОРЫ ДОСТУПА // Приведенные выше члены доступны для любого другого // класса. Чтобы определить доступы, используются модификаторы доступа: // - default: Если модификаторы доступа отсутствуют, атрибут доступен // только для классов внутри одного пакета. // - public: атрибут доступен из любого другого класса. // - protected: То же самое, что и default, плюс он доступен для подклассов. // - private: доступен только внутри объявленного класса. class Dog { private String name; private int age; void bark() { System.out.println("Bark!"); } void rename(String newName) { name = newName; } public String getName() { return name; } public void setAge(int newAge) { if(newAge > 0) age = newAge; } public int getAge() { return age; } }
Принципы ООП
Абстракция
Абстракция – это выделение основных, наиболее значимых характеристик объекта и игнорирование второстепенных.
Любой составной объект реального мира – это абстракция. Говоря «ноутбук», вам не требуется дальнейших пояснений, вроде того, что это организованный набор пластика, металла, жидкокристаллического дисплея и микросхем. Абстракция позволяет игнорировать нерелевантные детали, поэтому для нашего сознания это один из главных способов справляться со сложностью реального мира. Если б, подходя к холодильнику, вы должны были иметь дело с отдельно металлом корпуса, пластиковыми фрагментами, лакокрасочным слоем и мотором, вы вряд ли смогли бы достать из морозилки замороженную клубнику.
Полиморфизм
Полиморфизм подразумевает возможность нескольких реализаций одной идеи. Простой пример: у вас есть класс «Персонаж», а у него есть метод «Атаковать». Для воина это будет означать удар мечом, для рейнджера – выстрел из лука, а для волшебника – чтение заклинания «Огненный Шар». В сущности, все эти три действия – атака, но в программном коде они будут реализованы совершенно по-разному.
Наследование
Это способность одного класса расширять понятие другого, и главный механизм повторного использования кода в ООП. Вернёмся к нашему автосимулятору. На уровне абстракции «Автотранспорт» мы не учитываем особенности каждого конкретного вида транспортного средства, а рассматриваем их «в целом». Если же более детализировано приглядеться, например, к грузовикам, то окажется, что у них есть такие свойства и возможности, которых нет ни у легковых, ни у пассажирских машин. Но, при этом, они всё ещё обладают всеми другими характеристиками, присущими автотранспорту.
Мы могли бы сделать отдельный класс «Грузовик», который является наследником «Автотранспорта». Объекты этого класса могли бы определять все прошлые атрибуты (цвет, год выпуска), но и получить новые. Для грузовиков это могли быть грузоподъёмность, снаряженная масса и наличие жилого отсека в кабине. А методом, который есть только у грузовиков, могла быть функция сцепления и отцепления прицепа.
Инкапсуляция
Инкапсуляция – это ещё один принцип, который нужен для безопасности и управления сложностью кода. Инкапсуляция блокирует доступ к деталям сложной концепции. Абстракция подразумевает возможность рассмотреть объект с общей точки зрения, а инкапсуляция не позволяет рассматривать этот объект с какой-либо другой.
Вы разработали для муниципальных служб класс «Квартира». У неё есть свойства вроде адреса, метража и высоты потолков. И методы, такие как получение информации о каждом из этих свойств и, главное, метод, реализующий постановку на учёт в Росреестре. Это готовая концепция, и вам не нужно чтобы кто-то мог добавлять методы «открыть дверь» и «получить место хранения денег». Это А) Небезопасно и Б) Избыточно, а также, в рамках выбранной реализации, не нужно. Работникам Росреестра не требуется заходить к вам домой, чтобы узнать высоту потолков – они пользуются только теми документами, которые вы сами им предоставили.