TGTGInsightаналитика telegramLIVE / telegram public index
← Программирование для гуманитариев
Программирование для гуманитариев avatar

TGINSIGHT POST

Post #388

@it_human

Программирование для гуманитариев

Просмотры3,480Количество просмотров
Опубликован18 янв.18.01.2021, 13:02
Содержимое поста

Содержимое

ООП. Абстрактные классы Если вы пропустили предыдущие посты об ООП, советую начать с них: В предыдущих сериях: 1. Что такое классы 2. Что такое объекты классов и как их создавать. Конструкторы 3. Что такое ООП 4. Принципы ООП: абстракция. Инкапсуляция 5. Принципы ООП: наследование Сегодня продолжаем тему наследования. О том, стоит ли использовать наследование в своем коде, ведутся нешуточные баталии. Например, есть мнение, что композиция чуть ли не всегда лучше наследования. Под композицией тут имеется в виду, что один класс можно сделать атрибутом другого класса, и таким образом избежать иерархии наследования. Ещё одно мнение - наследоваться лучше только от абстрактных классов. Но что же это значит? Вспомним наш класс BaseUser из поста про наследование. Чтобы использовать его как абстрактный класс, мы не должны создавать его экземпляры. То есть объектов типа user = new BaseUser() в коде существовать вообще не может. Абстрактный класс нужен только для того, чтобы от него наследовались другие классы. Например, мы можем создать классы User(BaseUser) (обычный пользователь), AdminUser(BaseUser), ModeratorUser(BaseUser) - каждый из них наследуется от абстрактного класса BaseUser и заимствует его свойства. Мы можем создать объекты этих классов, но не базового класса - родителя. Часто в абстрактных классах есть абстрактные методы - то есть такие методы, которые не реализованы в данном классе. Например: class BaseUser() { function sayHello() { throw new NotImplementedException() } } У базового класса BaseUser метод sayHello абстрактный - он не реализован (точнее, реализация есть, но она просто бросает исключение). Таким образом, каждый класс, который наследуется от BaseUser должен будет предоставить свою реализацию метода sayHello. Иначе при вызове этого метода произойдёт ошибка. Существует еще такой тип абстрактных классов как интерфейс. Интерфейс обычно не реализует ни одного метода, в нём все методы абстрактные. Но каждый потомок, который наследуется от интерфейса обязан реализовать эти методы. Интерфейс по сути задаёт требования для своих потомков. Возьмём в качестве примера опять пульт от телевизора. В случае с современными телевизорами пульт - это не обязательно пластиковая коробочка с кнопками, вместо пульта можно использовать и android/ios - приложения, и разные устройства из серии «умный дом». Но чтобы их можно было использовать для управления телевизором, нужно чтобы у них был общий интерфейс - они должны уметь переключать каналы, включать/выключать телевизор и так далее. Эти общие требования к этим устройствам можно вынести в класс-интерфейс - он ничего не реализует сам, а скорее задает стандарт: class IRemote() { // методы не реализованы function turnOn() function turnOff() function nextChannel() … } Для того, чтобы сделать устройство для управления телевизором, нужно написать класс, который будет реализовывать все методы интерфейса IRemote. Я намерено стараюсь рассказывать о наследовании и связанных понятиях без привязки к отдельным языкам программирования. Каждый объектно-ориентированный язык имеет свою реализацию ООП. Например, в одних языках есть ключевое слово abstract для обозначения абстрактных классов, в других языках его нет, и абстрактный класс можно создать только полагаясь на «джентельменские соглашения» - то есть как бы договориться с другими разработчиками проекта, что мы не будем создавать объекты этого класса. В одних языках есть такой отдельный тип как Interface, в других можно имитировать поведение интерфейса с помощью обычных классов. В C++ есть еще, например, такая сущность как виртуальные классы и методы - но всё это особенности конкретных языков, и рассматривать их имеет смысл в том случае, если вы углубляетесь именно в эти языки.