Объектно-ориентированный подход. Объектно_ориентированный_подход. Объектно ориентированный подход Мэтт Вайсфельд 5е международное издание ббк 32. 973. 2018
Скачать 5.43 Mb.
|
48 Shape содержит метод Draw , Circle переопределит этот метод и обеспечит соб- ственный метод Draw() . Переопределение, в сущности, означает замену реали- зации родительского класса на реализацию из дочернего класса. Допустим, у вас имеется массив из трех форм — Circle , Square и Star . Даже если вы будете рассматривать их все как объекты Shape и отправите сообщение Draw каждому объекту Shape , то конечный результат для каждого из них будет разным, поскольку Circle , Square и Star обеспечивают фактические реализации. Одним словом, каждый класс способен реагировать на один и тот же метод Draw не так, как другие, и рисовать соответствующую фигуру. Это и понимается под поли- морфизмом. Взгляните на следующий класс Shape : public abstract class Shape{ private double area; public abstract double getArea(); } Класс Shape включает атрибут с именем area , который содержит значение пло- щади фигуры. Метод getArea() включает идентификатор с именем abstract Когда метод определяется как abstract , подкласс должен обеспечивать реали- зацию для этого метода; в данном случае Shape требует, чтобы подклассы обе- спечивали реализацию getArea() . А теперь создадим класс с именем Circle , который будет наследовать от Shape (ключевое слово extends будет указывать на то, что Circle наследует от Shape ): public class Circle extends Shape{ double radius; public Circle(double r) { radius = r; } public double getArea() { area = 3.14*(radius*radius); return (area); } } Здесь мы познакомимся с новой концепцией под названием конструктор. Класс Circle содержит метод с таким же именем — Circle . Если имя метода 49 Полиморфизм. . оказывается аналогичным имени класса и при этом не предусматривается возвращаемого типа, то это особый метод, называемый конструктором. Счи- тайте конструктор точкой входа для класса, где создается объект. Конструктор хорошо подходит для выполнения инициализаций и задач, связанных с за- пуском. Конструктор Circle принимает один параметр, представляющий радиус, и при- сваивает его атрибуту radius класса Circle Класс Circle также обеспечивает реализацию для метода getArea , изначально определенного как abstract в классе Shape Мы можем создать похожий класс с именем Rectangle : public class Rectangle extends Shape{ double length; double width; public Rectangle(double l, double w){ length = l; width = w; } public double getArea() { area = length*width; return (area); } } Теперь мы можем создавать любое количество классов прямоугольников, кру- гов и т. д. и вызывать их метод getArea() . Ведь мы знаем, что все классы прямо- угольников и кругов наследуют от Shape , а все классы Shape содержат метод getArea() . Если подкласс наследует абстрактный метод от суперкласса, то он должен обеспечивать конкретную реализацию этого метода, поскольку иначе он сам будет абстрактным классом (см. рис. 1.18, где приведена UML-диаграмма). Этот подход также обеспечивает механизм для довольно легкого создания дру- гих, новых классов. Таким образом, мы можем создать экземпляры классов Shape следующим путем: Circle circle = new Circle(5); Rectangle rectangle = new Rectangle(4,5); Затем, используя такую конструкцию, как стек, мы можем добавить в него классы Shape : stack.push(circle); stack.push(rectangle); Глава.1..Введение.в.объектно-ориентированные.концепции 50 Рис. 1.18. UML-диаграмма.Shape ЧТО ТАКОЕ СТЕК? _____________________________________________________________________ Стек.—.это.структура.данных,.представляющая.собой.систему.«последним.пришел.—. первым.ушел»..Это.как.стопка.монет.в.форме.цилиндра,.которые.вы.складываете. одна.на.другую..Когда.вам.потребуется.монета,.вы.снимете.верхнюю.монету,.которая. при.этом.будет.последней.из.тех,.что.вы.положили.в.стопку..Вставка.элемента.в.стек. означает,.что.вы.добавляете.его.на.вершину.стека.(подобно.тому,.как.вы.кладете. следующую.монету.в.стопку)..Удаление.элемента.из.стека.означает,.что.вы.убирае- те.последний.элемент.из.стека.(подобно.снятию.верхней.монеты). Теперь переходим к увлекательной части. Мы можем очистить стек, и нам при этом не придется беспокоиться о том, какие классы Shape в нем находятся (мы просто будем знать, что они связаны с фигурами): while ( !stack.empty()) { Shape shape = (Shape) stack.pop(); System.out.println ("Площадь = " + shape.getArea()); } В действительности мы отправляем одно и то же сообщение всем Shape : shape.getArea() Однако фактическое поведение, которое имеет место, зависит от типа фигуры. Например, Circle вычисляет площадь круга, а Rectangle — площадь прямо- угольника. На самом деле (и в этом заключается ключевая концепция) мы от- правляем сообщение классам Shape и наблюдаем разное поведение в зависимо- сти от того, какие подклассы Shape используются. Этот подход направлен на обеспечение стандартизации определенного интер- фейса среди классов, а также приложений. Представьте себе приложение из 51 Композиция. . офисного пакета, которое позволяет обрабатывать текст, и приложение для работы с электронными таблицами. Предположим, что они оба включают класс с именем Office , который содержит интерфейс с именем print() . Этот print() необходим всем классам, являющимся частью офисного пакета. Любопытно, но несмотря на то, что текстовый процессор и табличная программа вызывают интерфейс print() , они делают разные вещи: один выводит текстовый документ, а другая — документ с электронными таблицами. ПОЛИМОРФИЗМ С КОМПОЗИЦИЕЙ __________________________________________________ В.так.называемом.классическом.объектно-ориентированном.программировании. полиморфизм.традиционно.выполняется.наследованием..Но.есть.и.способ.выпол- нить.полиморфизм.с.применением.композиции..Мы.обсудим.такой.случай.в.главе.12. «Принципы.объектно-ориентированного.проектирования.SOLID». Композиция Вполне естественно представлять себе, что одни объекты содержат другие объ- екты. У телевизора есть тюнер и экран. У компьютера есть видеокарта, клавиа- тура и жесткий диск. Хотя компьютер сам по себе можно считать объектом, его жесткий диск тоже считается полноценным объектом. Фактически вы могли бы открыть системный блок компьютера, достать жесткий диск и подержать его в руке. Как компьютер, так и его жесткий диск считаются объектами. Просто компьютер содержит другие объекты, например жесткий диск. Таким образом, объекты зачастую формируются или состоят из других объек- тов — это и есть композиция. Абстрагирование Точно так же как и наследование, композиция обеспечивает механизм для соз- дания объектов. Я сказал бы, что фактически есть только два способа создания классов из других классов: наследование и композиция. Как мы уже видели, на- следование позволяет одному классу наследовать от другого. Поэтому мы можем абстрагировать атрибуты и поведения для общих классов. Например, как со- баки, так и кошки относятся к млекопитающим, поскольку собака является экземпляром млекопитающего так же, как и кошка. Благодаря композиции мы к тому же можем создавать классы, вкладывая одни классы в другие. Взглянем на отношение между автомобилем и двигателем. Преимущества раз- деления двигателя и автомобиля очевидны. Создавая двигатель отдельно, мы сможем использовать его в разных автомобилях, не говоря уже о других преиму- ществах. Однако мы не можем сказать, что двигатель является экземпляром автомобиля. Это будет просто неправильно звучать, если так выразиться (а по- скольку мы моделируем реальные системы, это нам и нужно). Вместо этого для Глава.1..Введение.в.объектно-ориентированные.концепции 52 описания отношений композиции мы используем словосочетание содержит как часть. Автомобиль содержит как часть двигатель. Отношения «содержит как часть» Хотя отношения наследования считаются отношениями «является экземпля- ром» по тем причинам, о которых мы уже говорили ранее, отношения компози- ции называются отношениями «содержит как часть». Если взять пример из приводившегося ранее раздела, то телевизор содержит как часть тюнер, а так- же экран. Телевизор, несомненно, не является тюнером, поэтому здесь нет ни- каких отношений наследования. В том же духе частью компьютера является видеокарта, клавиатура и жесткий диск. Тема наследования, композиции и того, как они соотносятся друг с другом, очень подробно разбирается в главе 7. Резюме При рассмотрении объектно-ориентированных технологий нужно много чего охватить. Однако по завершении чтения этой главы у вас должно сложиться хорошее понимание следующих концепций. Инкапсуляция. Инкапсуляция данных и поведений в одном объекте имеет первостепенное значение в объектно-ориентированной разработке. Один объект будет содержать как свои данные, так и поведения и сможет скрыть то, что ему потребуется, от других объектов. Наследование. Класс может наследовать от другого класса и использовать преимущества атрибутов и методов, определяемых суперклассом. Полиморфизм. Означает, что схожие объекты способны по-разному отвечать на одно и то же сообщение. Например, у вас может быть система с множеством фигур. Однако круг, квадрат и звезда рисуются по-разному. Используя полимор- физм, вы можете отправить одно и то же сообщение (например, Draw ) объ- ектам, на каждый из которых возлагается обязанность по рисованию соот- ветствующей ему фигуры. Композиция. Означает, что объект формируется из других объектов. В этой главе рассмотрены фундаментальные объектно-ориентированные кон- цепции, в которых к настоящему времени вы уже должны хорошо разбираться. Глава 2 КАК МЫСЛИТЬ ОБЪЕКТНО В главе 1 вы изучили фундаментальные объектно-ориентированные концепции. В остальной части этой книги мы тщательнее разберем эти концепции и по- знакомимся с некоторыми другими. Для грамотного подхода к проектированию необходимо учитывать много факторов, независимо от того, идет ли речь об объектно-ориентированном проектировании или каком-то другом. В качестве основной единицы при объектно-ориентированном проектировании выступает класс. Желаемым конечным результатом такого проектирования является на- дежная и функциональная объектная модель, другими словами, полная система. Как и в случае с большинством вещей в жизни, нет какого-то одного правиль- ного или ошибочного подхода к устранению проблем. Обычно бывает много путей решения одной и той же проблемы. Поэтому, пытаясь выработать объ- ектно-ориентированное решение, не зацикливайтесь на том, чтобы постараться с первого раза все идеально спроектировать (кое-что всегда можно будет усо- вершенствовать). В действительности вам потребуется прибегнуть к мозговому штурму и позволить мыслительному процессу пойти в разных направлениях. Не старайтесь соответствовать каким-либо стандартам или соглашениям, пы- таясь решить проблему, поскольку важно лишь быть креативным. Фактически на самом старте процесса не стоит даже начинать задумываться о конкретном языке программирования. Первым пунктом повестки дня должно быть определение и решение бизнес-проблем. Займитесь сперва концептуаль- ным анализом и проектированием. Задумывайтесь о конкретных технологиях, только если они будут существенны для решения бизнес-проблем. Например, нельзя спроектировать беспроводную сеть без беспроводной технологии. Од- нако часто будет случаться так, что вам придется обдумывать сразу несколько программных решений. Таким образом, перед тем как приступать к проектированию системы или даже класса, следует поразмыслить над соответствующей задачей и повеселиться! В этой главе мы рассмотрим изящное искусство и науку объектно-ориентиро- ванного мышления. Любое фундаментальное изменение в мышлении не является тривиальным. Например, ранее много говорилось о переходе со структурной разработки на Глава.2..Как.мыслить.объектно 54 объектно-ориентированную. Один из побочных эффектов ведущихся при этом дебатов заключается в ошибочном представлении, что структурная и объектно- ориентированная разработки являются взаимоисключающими. Однако это не так. Как мы уже знаем из нашего исследования оберток, структурная и объ ектно- ориентированная разработки сосуществуют. Фактически, создавая объектно- ориентированное приложение, вы повсеместно используете структурные конструкции. Мне никогда не доводилось видеть программу, объектно-ориен- тированную или любую другую, которая не задействует циклы, операторы if и т. д. Кроме того, переход на объектно-ориентированное проектирование не потребует каких-либо затрат. Чтобы перейти с FORTRAN на COBOL или даже C, вам потребуется изучить новый язык программирования, однако для перехода с COBOL на C++, C# . NET, Visual Basic .NET, Objective-C или Java вам придется освоить новое мыш- ление. Здесь всплывает избитое выражение объектно-ориентированная пара- дигма. При переходе на объектно-ориентированный язык вам сначала потребу- ется потратить время на изучение объектно-ориентированных концепций и освоение соответствующего мышления. Если такая смена парадигмы не про- изойдет, то случится одна из двух вещей: либо проект не окажется по-настоящему объектно-ориентированным по своей природе (например, он будет задействовать C++ без использования объектно-ориентированных конструкций), либо он окажется полной объектно-неориентированной неразберихой. В этой главе рассматриваются три важные вещи, которые вы можете сделать для того, чтобы хорошо освоить объектно-ориентированное мышление: знать разницу между интерфейсом и реализацией; мыслить более абстрактно; обеспечивать для пользователей минимальный интерфейс из возможных. Мы уже затронули некоторые из этих концепций в главе 1, а теперь разберемся в них более подробно. Разница между интерфейсом и реализацией Как мы уже видели в главе 1, один из ключей к грамотному проектированию — понимание разницы между интерфейсом и реализацией. Таким образом, при проектировании класса важно определить, что пользователю требуется знать, а что нет. Механизм сокрытия данных, присущий инкапсуляции, представляет собой инструмент, позволяющий скрывать от пользователей несущественные данные. Помните пример с тостером из главы 1? Тостер или любой электроприбор, если на то пошло, подключается к интерфейсу, которым является электриче- ская розетка (рис. 2.1). Все электроприборы получают доступ к необходимому 55 Разница.между.интерфейсом.и.реализацией. . элект ричеству через электрическую розетку, которая соответствует нужному интерфейсу. Тостеру не нужно что-либо знать о реализации или о том, как вырабатывается электричество. Для него важно лишь то, чтобы работающая на угле или атомная электростанция могла вырабатывать электричество, — этому электроприбору все равно, какая из станций будет делать это, при ус- ловии, что интерфейс работает соответствующим образом, то есть корректно и надежно. Рис. 2.1. Повторно.приведенный.пример.с.электростанцией ПРЕДОСТЕРЕЖЕНИЕ __________________________________________________________________ Не.путайте.концепцию.интерфейса.с.терминами.вроде.«графический.интерфейс. пользователя».(GUI.—.Graphical.User.Interface)..Несмотря.на.то.что.графический. интерфейс.пользователя,.как.видно.из.его.названия,.представляет.собой.интерфейс,. используемый.здесь.термин.является.более.общим.по.своей.природе.и.не.ограни- чивается.понятием.графического.интерфейса. В качестве другого примера рассмотрим автомобиль. Интерфейс между вами и автомобилем включает такие компоненты, как руль, педаль газа, педаль тормоза и переключатель зажигания. Когда речь идет об управлении автомо- билем, для большинства людей, если отбросить вопросы эстетики, главным является то, как он заводится, разгоняется, останавливается и т. д. Реализация, чем, по сути, является то, чего вы не видите, мало интересует среднестатисти- ческого водителя. Фактически большинство людей даже не способно иденти- фицировать определенные компоненты, например каталитический преобра- зователь или сальник. Однако любой водитель узнает руль и будет в курсе, как его использовать, поскольку это общий интерфейс. Устанавливая стан- дартный руль в автомобилях, производители могут быть уверены в том, что люди из их потенциального круга покупателей смогут использовать выпуска- емую ими продукцию. Однако если какой-нибудь производитель решит установить вместо руля джой- стик, то большинство водителей будут разочарованы, а продажи таких автомо- билей могут оказаться низкими (подобная замена устроит разве что отдельных эклектиков, которым нравится «двигаться против течения»). С другой стороны, если мощность и эстетика не изменятся, то среднестатистический водитель Глава.2..Как.мыслить.объектно 56 ничего не заметит, даже если производитель изменит двигатель (часть реализа- ции) выпускаемых автомобилей. Отметим, что заменяемые двигатели должны быть идентичны, насколько это возможно во всех отношениях. Замена четырехцилиндрового двигателя на восьмицилиндровый изменит правила и, вероятно, не будет работать с другими компонентами, которые взаимодействуют с двигателем, точно так же как из- менение тока с переменного на постоянный будет влиять на правила в примере силовой установки. Двигатель является частью реализации, а руль — частью интерфейса. Изме- нения в реализации не должны оказывать влияния на водителя, в то время как изменения в интерфейсе могут это делать. Водитель заметил бы эстетические изменения руля, даже если бы тот функционировал так же, как и раньше. Не- обходимо подчеркнуть, что изменения в двигателе, заметные для водителя, нарушают это правило. Например, изменение, которое приведет к заметной потери мощности, в действительности будет изменением интерфейса. |