class Животное: def издать_звук(self): raise NotImplementedError("Этот метод должен быть реализован в подклассе") class Кот(Животное): def издать_звук(self): print("Мяу!") class Собака(Животное): def издать_звук(self): print("Гав!") животные = [Кот(), Собака()] for животное in животные: животное.издать_звук() # Output: Мяу! Гав!В этом примере метод
издать_звуквызывается для объектов различных классов (
Коти
Собака), и каждый объект реализует этот метод по-своему. В Java полиморфизм достигается через интерфейсы и абстрактные классы:
abstract class Животное { abstract void издатьЗвук(); } class Кот extends Животное { @Override void издатьЗвук() { System.out.println("Мяу!"); } } class Собака extends Животное { @Override void издатьЗвук() { System.out.println("Гав!"); } } public class Main { public static void main(String[] args) { Животное[] животные = { new Кот(), new Собака() }; for (Животное животное : животные) { животное.издатьЗвук(); // Output: Мяу! Гав! } } }Здесь абстрактный метод
издатьЗвукреализуется в классах
Коти
Собака, и тот же метод вызывает различные реализации в зависимости от объекта. Давайте теперь посмотрим примеры кейсов, где может быть актуален полиморфизм: 1. Фигуры Предположим, у нас есть несколько различных фигур, и мы хотим рассчитать их площадь. Полиморфизм позволяет нам использовать один интерфейс для разных типов фигур.
class Фигура: def площадь(self): raise NotImplementedError("Этот метод должен быть реализован в подклассе") class Круг(Фигура): def __init__(self, радиус): self.радиус = радиус def площадь(self): return 3.14159 * self.радиус ** 2 class Прямоугольник(Фигура): def __init__(self, ширина, высота): self.ширина = ширина self.высота = высота def площадь(self): return self.ширина * self.высота фигуры = [Круг(5), Прямоугольник(3, 4)] for фигура in фигуры: print(f"Площадь: {фигура.площадь()}")2. Платежные системы Используем полиморфизм для различных способов проведения платежей.
class Платеж(ABC): @abstractmethod def провести_платеж(self, сумма): pass class КредитнаяКарта(Платеж): def провести_платеж(self, сумма): print(f"Платеж проведён на сумму {сумма} с кредитной карты") class PayPal(Платеж): def провести_платеж(self, сумма): print(f"Платеж проведён на сумму {сумма} через PayPal") платежи = [КредитнаяКарта(), PayPal()] for платеж in платежи: платеж.провести_платеж(100)Полиморфизм — ключевая концепция ООП. Он делает ваш код более универсальным и удобным для использования и расширения. Это особенно полезно, когда ваш проект растёт и требует поддержки различных типов объектов. #простымисловами #ооп #полиморфизм
class Животное: def издать_звук(self): raise NotImplementedError("Этот метод должен быть реализован в подклассе") class Кот(Животное): def издать_звук(self): print("Мяу!") class Собака(Животное): def издать_звук(self): print("Гав!") животные = [Кот(), Собака()] for животное in животные: животное.издать_звук() # Output: Мяу! Гав!В этом примере метод
издать_звуквызывается для объектов различных классов (
Коти
Собака), и каждый объект реализует этот метод по-своему. #### Пример 2: Полиморфизм в Java В Java полиморфизм достигается через интерфейсы и абстрактные классы.
abstract class Животное { abstract void издатьЗвук(); } class Кот extends Животное { @Override void издатьЗвук() { System.out.println("Мяу!"); } } class Собака extends Животное { @Override void издатьЗвук() { System.out.println("Гав!"); } } public class Main { public static void main(String[] args) { Животное[] животные = { new Кот(), new Собака() }; for (Животное животное : животные) { животное.издатьЗвук(); // Output: Мяу! Гав! } } }Здесь абстрактный метод
издатьЗвукреализуется в классах
Коти
Собака, и тот же метод вызывает различные реализации в зависимости от объекта. ### Применение полиморфизма #### Пример 1: Фигуры Предположим, у нас есть несколько различных фигур, и мы хотим рассчитать их площадь. Полиморфизм позволяет нам использовать один интерфейс для разных типов фигур.
class Фигура: def площадь(self): raise NotImplementedError("Этот метод должен быть реализован в подклассе") class Круг(Фигура): def __init__(self, радиус): self.радиус = радиус def площадь(self): return 3.14159 * self.радиус ** 2 class Прямоугольник(Фигура): def __init__(self, ширина, высота): self.ширина = ширина self.высота = высота def площадь(self): return self.ширина * self.высота фигуры = [Круг(5), Прямоугольник(3, 4)] for фигура in фигуры: print(f"Площадь: {фигура.площадь()}")#### Пример 2: Платежные системы Используем полиморфизм для различных способов проведения платежей.
class Платеж(ABC): @abstractmethod def провести_платеж(self, сумма): pass class КредитнаяКарта(Платеж): def провести_платеж(self, сумма): print(f"Платеж проведён на сумму {сумма} с кредитной карты") class PayPal(Платеж): def провести_платеж(self, сумма): print(f"Платеж проведён на сумму {сумма} через PayPal") платежи = [КредитнаяКарта(), PayPal()] for платеж in платежи: платеж.провести_платеж(100)### Чем полиморфизм отличается от других концепций? - **Наследование**: Позволяет классам наследовать свойства и методы от другого класса. - Инкапсуляция: Скрывает детали реализации и предоставляет доступ к данным через методы. - Абстракция: Скрывает сложную реализацию и предоставляет простой интерфейс. Полиморфизм: Фокусируется на способности использовать один и тот же интерфейс для различных типов объектов, что позволяет более универсально и гибко работать с кодом. ### Заключение
class Кот: def __init__(self, имя): self.__имя = имя # Скрытый атрибут def получить_имя(self): return self.__имя # Метод для получения скрытого атрибута def мяукать(self): print(f"{self.__имя} говорит: Мяу!") кот = Кот("Мурзик") print(кот.получить_имя()) # Output: Мурзик кот.мяукать() # Output: Мурзик говорит: Мяу! # Попытка доступа к скрытому атрибуту напрямую # print(кот.__имя) # Это вызовет ошибкуВ этом примере атрибут
__имяскрыт от внешнего доступа, и доступ к нему можно получить только через метод
получить_имя. Давайте рассмотрим пример из Java. Здесь инкапсуляция достигается с помощью модификаторов доступа (private, protected, public) и методов getter/setter.
public class Кот { private String имя; // Скрытый атрибут public Кот(String имя) { this.имя = имя; } public String getИмя() { // Метод для получения скрытого атрибута return имя; } public void мяукать() { System.out.println(имя + " говорит: Мяу!"); } public static void main(String[] args) { Кот кот = new Кот("Мурзик"); System.out.println(кот.getИмя()); // Output: Мурзик кот.мяукать(); // Output: Мурзик говорит: Мяу! // Попытка доступа к скрытому атрибуту напрямую // System.out.println(кот.имя); // Это вызовет ошибку } }В этом примере атрибут
имяобъявлен как
privateи доступен только через метод
getИмя. Где применяется? Инкапсуляция помогает скрыть детали внутренней структуры объекта, например, банковского счёта.
class БанкСчет: def __init__(self, баланс=0): self.__баланс = баланс # Скрытый атрибут def пополнить(self, сумма): if сумма > 0: self.__баланс += сумма def вывести(self, сумма): if сумма > 0 и self.__баланс >= сумма: self.__баланс -= сумма def получить_баланс(self): return self.__баланс счет = БанкСчет() счет.пополнить(100) счет.вывести(30) print(счет.получить_баланс()) # Output: 70Также позволяет управлять доступом к критическим операциям.
class Пользователь: def __init__(self, имя, пароль): self.__имя = имя self.__пароль = пароль # Скрытый атрибут def проверить_пароль(self, ввод): return self.__пароль == ввод пользователь = Пользователь("Иван", "12345") print(пользователь.проверить_пароль("12345")) # Output: True print(пользователь.проверить_пароль("54321")) # Output: FalseТеперь вы знакомы с тремя составляющими ООП. Нам осталось разобраться в полиморфизме. Если формат заходит — поставьте ❤️, я буду знать, что пишу не зря. А замечания можете написать в комментарии👇 #простымисловами #ооп #инкапсуляция
from abc import ABC, abstractmethod class Животное(ABC): @abstractmethod def издать_звук(self): pass class Кот(Животное): def издать_звук(self): print("Мяу!") class Собака(Животное): def издать_звук(self): print("Гав!") животные = [Кот(), Собака()] for животное in животные: животное.издать_звук()Здесь
Животное— это абстрактный класс с абстрактным методом
издать_звук, который обязаны реализовать все дочерние классы, такие как
Коти
Собака. Пример 2: Интерфейсы (в других языках) В языках программирования, таких как Java или C#, существуют интерфейсы, которые определяют набор методов, которые должны быть реализованы классами.
interface Животное { void издатьЗвук(); } class Кот implements Животное { public void издатьЗвук() { System.out.println("Мяу!"); } } class Собака implements Животное { public void издатьЗвук() { System.out.println("Гав!"); } } public class Main { public static void main(String[] args) { Животное кот = new Кот(); Животное собака = new Собака(); кот.издатьЗвук(); // Output: Мяу! собака.издатьЗвук(); // Output: Гав! } }Здесь
Животное— это интерфейс, который определяется методом
издатьЗвук, что должен быть реализован в классах
Коти
Собака. Давайте теперь посмотрим, где применяется эта концепция в реальной жизни: 1. Управление пользователями. Абстракция позволяет создавать общие интерфейсы для работы с пользователями различных типов — например, администраторы и обычные пользователи.
from abc import ABC, abstractmethod class Пользователь(ABC): @abstractmethod def доступ(self): pass class Админ(Пользователь): def доступ(self): return "Полный доступ" class Гость(Пользователь): def доступ(self): return "Доступ в режиме чтения" пользователи = [Админ(), Гость()] for пользователь in пользователи: print(пользователь.доступ())2. Работа с данными. Часто используется, когда нужно создать общий интерфейс для работы с разными источниками данных.
from abc import ABC, abstractmethod class Репозиторий(ABC): @abstractmethod def получить_данные(self): pass class SQLРепозиторий(Репозиторий): def получить_данные(self): return "Данные из SQL базы данных" class APIРепозиторий(Репозиторий): def получить_данные(self): return "Данные из API" репозитории = [SQLРепозиторий(), APIРепозиторий()] for репозиторий in репозитории: print(репозиторий.получить_данные())3. Системы оплаты. Можно создать абстракцию для различной обработки платежей — кредитными картами, PayPal, Bitcoin и т.д.
class Платеж(ABC): @abstractmethod def провести_платеж(self, сумма): pass class КредитнаяКарта(Платеж): def провести_платеж(self, сумма): print(f"Платеж проведён на сумму {сумма} с кредитной карты") class PayPal(Платеж): def провести_платеж(self, сумма): print(f"Платеж проведён на сумму {сумма} через PayPal") платежи = [КредитнаяКарта(), PayPal()] for платеж in платежи: платеж.провести_платеж(100)#простымисловами #ооп
# Родительский (суперкласс) class Животное: def __init__(self, имя, возраст): self.имя = имя self.возраст = возраст def издать_звук(self): raise NotImplementedError("Этот метод должен быть определён в подклассе") def описание(self): return f"{self.имя} — {self.возраст} лет" # Дочерний класс Кот наследует от Животное class Кот(Животное): def издать_звук(self): return "Мяу!" # Дочерний класс Собака наследует от Животное class Собака(Животное): def издать_звук(self): return "Гав!" # Создаём объекты кот = Кот("Мурзик", 3) собака = Собака("Бобик", 5) # Используем методы print(кот.описание()) # Output: Мурзик — 3 лет print(кот.издать_звук()) # Output: Мяу! print(собака.описание()) # Output: Бобик — 5 лет print(собака.издать_звук()) # Output: Гав!Ключевые моменты в наследовании: 1. Конструктор родительского класса Для инициализации объектов дочернего класса важно вызвать конструктор родительского класса. В Python это делается с помощью функции
super().
class Животное: def __init__(self, имя, возраст): self.имя = имя self.возраст = возраст class Кот(Животное): def __init__(self, имя, возраст, цвет): super().__init__(имя, возраст) self.цвет = цвет кот = Кот("Пушок", 2, "серый") print(кот.описание()) # Output: Пушок — 2 лет print(кот.цвет) # Output: серый2. Переопределение методов Дочерний класс может переопределять методы родительского класса, изменяя их поведение.
class Животное: def __init__(self, имя, возраст): self.имя = имя self.возраст = возраст def издать_звук(self): return "Звук животного" class Кот(Животное): def издать_звук(self): return "Мяу!" кот = Кот("Мурзик", 3) print(кот.издать_звук()) # Output: Мяу!3. Множественное наследование Иногда подкласс может наследовать свойства и методы от нескольких родительских классов. Это полезно, но требует осторожности, чтобы избежать сложных зависимостей и конфликтов.
class Животное: def дышать(self): return "Дышу" class Летать: def летать(self): return "Летаю" class Птица(Животное, Летать): def издать_звук(self): return "Чирик" птица = Птица() print(птица.дышать()) # Output: Дышу print(птица.летать()) # Output: Летаю print(птица.издать_звук()) # Output: ЧирикВозможно, вы сейчас задаётесь вопросом где же это применяется на практике? Например, тут: 1. Интерфейсы GUI. При разработке графических интерфейсов часто используют наследование для создания различных элементов интерфейса. 2. Системы управления пользователями. В системах управления пользователями можно использовать наследование для создания различных ролей с различными уровнями доступа. 3. Игровые приложения. В играх классы персонажей могут быть наследуемыми, чтобы создавать различные типы персонажей. Наследование применяется практически везде, где это возможно. Чем быстрее вы поймёте его, тем скорее сможете раскрыть весь его потенциал. #простымисловами #ооп
class Кот: def __init__(self, имя): self.имя = имя def мяукать(self): print(f"{self.имя} говорит: Мяу!") мой_кот = Кот("Мурзик") мой_кот.мяукать()1. Наследование Наследование позволяет создавать новый класс на основе существующего. Это как брать основу от одного рецепта и добавлять свои изменения.
class Животное: def дышать(self): print("Дышу") class Кот(Животное): def мяукать(self): print("Мяу!") кот = Кот() кот.дышать() кот.мяукать()2. Абстракция Абстракция — это концепция, позволяющая скрыть сложность системы, выделяя только ключевые аспекты и упрощая взаимодействие с объектами. Это как пользоваться телевизором: вы знаете, какие кнопки нажимать, но не обязаны понимать, как работает вся электроника внутри. 3. Инкапсуляция Инкапсуляция — скрытие внутренней реализации объекта от внешнего мира и предоставление доступа только через определённые методы. Это как секретный ингредиент у шеф-повара, который скрыт от всех, кроме него.
class Кот: def __init__(self, имя): self.__имя = имя # сокрыто (private) def получить_имя(self): return self.__имя def мяукать(self): print(f"{self.__имя} говорит: Мяу!") кот = Кот("Мурзик") print(кот.получить_имя()) кот.мяукать()4. Полиморфизм Полиморфизм позволяет использовать один интерфейс для разных типов объектов. Это как использовать одного и того же шеф-повара, чтобы готовить по разным рецептам.
class Животное: def издать_звук(self): pass class Кот(Животное): def издать_звук(self): print("Мяу!") class Собака(Животное): def издать_звук(self): print("Гав!") животные = [Кот(), Собака()] for животное in животные: животное.издать_звук()Само собой тема ООП гораздо более обширна и содержит множество различных нюансов, которые не описать в одном посте. Но даже эти знания помогут вам в дальнейшем проще и быстрее разобраться во всех тонкостях. Если вам понравился пост, поставьте ❤️ и мы обязательно расскажем о чём-то ещё. #простымисловами #ооп