Всегда ли нужно создавать новые классы?
Начнем с вопроса, казалось бы, не имеющего никакого отношения к рассматриваемому вопросу, а именно - всегда ли нужно создавать новый класс для каждой новой задачи? Правильный ответ, конечно же, "нет". Это было бы странно и неэффективно. Могут быть ситуации, когда существующие классы по каким-либо причинам не устраивают архитектора, и тогда требуется создать новый класс. Следует, однако, избегать ситуаций, когда созданный класс (а точнее, его набор операций и атрибутов) практически повторяет существующий, лишь незначительно отличаясь от него. В общем случае, сказанное выше можно проиллюстрировать такой диаграммой (рис. 5):
Рисунок 5 - Иллюстрация примера
В дополнение можно назвать несколько причин, почему стоит использовать уже существующие классы:
Во-первых, идя этим путем, мы пользуемся плодами ранее принятых решений. Действительно, если когда-то мы уже решили некоторую проблему, зачем начинать все "с нуля", повторяя уже однажды проделанные действия?
Во-вторых, таким образом, мы делаем решение мобильным и расширяемым. Используя уже существующие классы и создавая на их основе новые, мы можем развивать решение практически неограниченно, добавляя лишь необходимые нам в данный момент детали - атрибуты и операции.
В-третьих, существующие классы, как правило, хорошо отлажены и показали себя в работе. Разработчику не надо тратить время на кодирование, отладку, тестирование и т. д., - мы работаем с хорошо отлаженным и проверенным временем кодом, который зарекомендовал себя в других проектах и в котором уже выявлено и исправлено большинство ошибок.
Понятия обобщенияили генерализациииграют очень важную роль в ООП, являясь одним из его базовых принципов.
Обобщение – это отношение между более общей сущностью, называемой суперклассом, и ее конкретным воплощением, называемым подклассом. Иногда обобщение называют отношениями типа "является", имея в виду, что одни сущности (например, круг, квадрат, треугольник) являются воплощением более общей сущности (например, класса "геометрическая фигура"). При этом все атрибуты и операции суперкласса независимо от модификаторов видимости входят в состав подкласса.
Обобщение (или, как часто говорят, наследование) на диаграммах обозначается очень просто - незакрашенной треугольной стрелкой, направленной на суперкласс (рис. 6).
Для того чтобы научиться эффективно моделировать наследование, обратимся к классикам, а именно к Г. Бучу. Он советует проводить эту процедуру в такой последовательности:
1. Найдите атрибуты, операции и обязанности, общие для двух или более классов из данной совокупности. Это позволит избежать ненужного дублирования структуры и функциональности объектов.
2. Вынесите эти элементы в некоторый общий суперкласс, а если такого не существует, то создайте новый класс.
3. Отметьте в модели, что подклассы наследуются от суперкласса, установив между ними отношение обобщения.
Рисунок 6 – Обозначение обобщения
А вот и пример применения этого подхода (рис. 7):
Рисунок 7 – Пример применения обобщения
Объекты разной природы (или говоря проще, разных классов) могут поддерживать один и тот же интерфейс именно так, как того ожидает пользователь. Примером тому может служить рассмотренная выше диаграмма с геометрическими фигурами. Все рассмотренные фигуры имеют, например, операцию рисования на экране. С точки зрения пользователя в каждом случае это одно и то же действие. Однако реализованы эти операции по-разному - ведь процедура изображения прямоугольника сильно отличается от подобной процедуры для круга. Но для пользователя это неважно: ведь сигнатура-то одна и та же. А возможно это благодаря еще одному из основных принципов ООП - полиморфизму. Как мы только что упомянули, работа механизма полиморфизма основана на совпадении сигнатуры метода, объявленного в интерфейсе, и сигнатуры самого метода. Методы внутри классов-потомков могут быть (и наверняка будут!) переопределены, их реализации будут различными, а сигнатуры останутся неизменными. Таким образом (и в этом легко ощутить мощь ООП), выполняя одни и те же операции, разные объекты могут вести себя по-разному.
Полиморфизм является основой для реализации механизма интерфейсов в языках программирования. Как только пользователь обращается к некоторой операции через интерфейс, определяется фактический класс объекта и вызывается соответствующая операция класса. Примеры полиморфизма можно увидеть в самых обыденных вещах, которыми мы пользуемся в повседневной жизни. Оглянитесь вокруг - мир построен по ООП, Например, всем привычная кредитная карточка, является интерфейсом для доступа к банковскому счету через банкомат (и не только), одинаково работает в любой стране, вот только ведет себя чуть-чуть по-разному, т. к. банкомат выдает деньги в местной валюте. Пример не очень корректный, но зато очень наглядный.
Инкапсуляция, наследование и полиморфизм, с которыми мы только что познакомились, являются теми самыми тремя китами, на которых держится ООП. Если вы поняли суть этих базовых принципов и осознали их истинную мощь, вы прошли большую часть пути, ведущего к полному овладению ООП как наиболее адекватной методикой описания (так и тянет сказать "проектирования") окружающего нас мира.
Дата добавления: 2021-07-22; просмотров: 426;