Как стать автором
Обновить

Почему мне кажется, что студентов учат ООП неправильно

ПрограммированиеАнализ и проектирование системИнтерфейсыООПУправление разработкой
Tutorial
Когда я учился в университете мне довольно тяжело было понять ООП (Объектно-ориентированное программирование), сейчас я понимаю, что просто нас учили ООП на не совсем ясных и правильных аналогиях и вообще, кажется, сами преподаватели не совсем понимали, в чем же суть ООП.

image

Вспомните, классические аналогии ООП, вот есть класс Домашние любимцы с методами «голос» и «есть», от него мы наследуем Кошку и Собаку и все хорошо.

Но тут приходит Света и приносит аквариумных рыбок, которые не разговаривают, а потом приходит Вася, которые приносит любимый кактус, которые не только не разговаривает, но и не ест.

Мы уже запутались, но Вовочка спрашивает: «а где в этом зоопарке статические методы, интерфейсы, абстрактные классы и чем отличается объект класса от самого класса?». Объяснить, несомненно, можно, но сложно. Понять, еще сложнее.

Или другой классический пример, вот есть прямоугольник, от которого так и хочется унаследовать квадрат (ну по логике, квадрат это частный случай прямоугольника), но у прямоугольника есть длина и ширина, а у квадрата только одна сторона. Что-то тут тоже запутано.

Теперь подумаем как объяснить ООП лучше?

Объектно-ориентированное программирование это не описание объектов реального мира (точнее не только и столько описание реального мира), оно появилось от техник проектирования (до появления всяких компьютеров) от всяких инженерных бюро, архитекторов зданий, проектировщиков техники и т.п.

image

Итак представим себе фирму, производящую самолеты и конструкторское бюро при этой фирме (ну, скажем, Боинг). Нам заказали несколько моделей: военный самолет, грузовой и пассажирский.

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

Код на Java
public abstract class ЧертежСамолета {  // чертеж нашей универсальной модели самолета;
        public abstract void взлет();
        public void полет() {
            // описание как наш самолет летит
        }
        public abstract void посадка();
 }


Второе, нам нужно описать требования для унифицированного самолета, у него должны быть определенны такие параметры как грузоподъемность, крейсерская и максимальная скорость, практический потолок (они могут отличаться у разных моделей, но они должны быть), он должен уметь взлетать и, крайне желательно, уметь садиться. Требования к самолетам это интерфейс.

Код на Java
public interface ТребованияКСамолету { // то что должен уметь наш самолет
        long getМаксимальнуюСкорость();
        double getГрузоподьемность();
        long getПрактическийПотолок();
        void взлет();
        void полет();
        void посадка();
}

public abstract class ЧертежСамолета implements ТребованияКСамолету {
    ...


Параметры унифицированного самолета, которые заданы, но еще не определенны, или действия, которые он должен делать (взлет/посадка) это виртуальные методы и члены класса.

Код на Java
public abstract class ЧертежСамолета {  // чертеж нашей универсальной модели самолета;
        public abstract void взлет(); // виртуальные метод
        public void полет() {
            // описание как наш самолет летит
        }
        public abstract void посадка(); // виртуальные метод
 }


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

Код на Java
public class ЧертежПассажирскогоСамолета extends ЧертежСамолета {  
       public int getКолВоПассажиров() {
              return 120;
        }
        public void взлет() {
            поздороваться_с_пассажирами();
            провести_инструктаж();
            получить_разрешение_на_взлет();
            взлететь():
        }
        ...
}
public class ЧертежВоенногоСамолета  extends ЧертежСамолета {  
       public int getКолВоРакет() {
              return 5;
        }
        public void взлет() {
            получить_приказ();
            доложить_командиру();
            взлететь():
        }
        ...
}


Если мы произведем реальный самолет это будет инстанс (объект) класса. Он построен по конкретным чертежам, но его параметры изменяются со временем, например, его максимальная и крейсерская скорость может чуть уменьшиться после определенных лет налета. То есть реальный существующий самолет это инстанс (объект) класса.

Код на Java
ЧертежСамолета тотСамыйПотрепанныйБоингНаКоторомМыЛетелиВТурцию = new ЧертежПассажирскогоСамолета();

тотСамыйПотрепанныйБоингНаКоторомМыЛетелиВТурцию.setПотрепаность(0.99);


image

У каждой модели самолета есть общие параметры, например, процент аварийности. Каждое происшествие с любым самолетом этой модели его может изменить. Это статические методы и переменные класса.

Код на Java
ЧертежПассажирскогоСамолета.setАварийностьМодели(0.0);


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

Код на Java
public class ЧертежПассажирскогоСамолета extends ЧертежСамолета {  
       ...
        public void посадка() {
            предупредить_пассажиров();
            проверить_все_пассажирские_места();
            получить_разрешение_на_посадку();
            сесть():
        }
        ...
}
public class ЧертежВоенногоСамолета  extends ЧертежСамолета {  
        public void посадка() {
            получить_приказ();
            доложить_командиру();
            сесть():
        }
        ...
}


Если мы делаем самолет, но двигатель разрабатывает другая команда, нам проще не указывать его на самом чертеже самолета (тем более что один двигатель может использовать на большом количестве самолетов), а только указать «смотри чертеж такого-то двигателя». Это композиция.

Код на Java
public class ЧертежПассажирскогоСамолета extends ЧертежСамолета {  
       private ЧертежДвигателя двигатель = new ДвигательМ45ФирмыАстинМартин()
        ...
}


Если мы разрабатываем трап, подходящий под этот тип самолета (и, возможно, другие подробные самолеты), пилот самолета при приземлении просит подать именно этот трап. Это будет ассоциация.

Если мы создали модель пассажирского самолета на 120 мест, а потом чуть-чуть доработали увеличив количество мест до 130 (за счет сокращения бизнес класса), нам не потребуется создавать новый чертеж, достаточно лишь указать изменения. Тут же становится легко понятно, почему если поменяется что-то в чертеже модели самолета на 120 мест, так же измениться самолет на 130 мест, так мы не делаем копию чертежей, мы только описываем, что изменилось в проекте. Это наследование.

Код на Java
public class ЧертежПассажирскогоСамолетаНа130Мест extends ЧертежПассажирскогоСамолета {  
       @Override
        public int getКолВоПассажиров() {
              return 130;
        }
        ...
}


Вопрос зачем вообще нужно ООП?

Все просто, вы не будете разрабатывать каждый самолет с нуля, вы в любом случае возьмете успешную модель и просто доработаете ее. Вам нет смысла создавать двигатель только для одного самолета, его может разработать другая совсем команда. Чтобы вставить двигатель в самолет, но должен соответствовать каким-то параметрам (размеры, тяга, топливо), то есть без спецификаций-контрактов (интерфейсов) вам не обойтись.

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

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

Спасибо за внимание!

P.S. Другие мои статьи (например, шпаргалку по Java SE) можно найти в моем профиле
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Такой метод объяснения ООП вам кажется нагляднее и проще чем раньше?
40.37% да 608
30.48% возмжно 459
13.75% без разницы 207
2.12% нам так же объясняли в Университете 32
13.28% нет 200
Проголосовали 1506 пользователей. Воздержались 218 пользователей.
Теги:опп
Хабы: Программирование Анализ и проектирование систем Интерфейсы ООП Управление разработкой
Всего голосов 68: ↑53 и ↓15+38
Просмотры189K
Комментарии Комментарии 473

Похожие публикации

Лучшие публикации за сутки