Объектно-ориентированный подход. Объектно_ориентированный_подход. Объектно ориентированный подход Мэтт Вайсфельд 5е международное издание ббк 32. 973. 2018
Скачать 5.43 Mb.
|
Наследование В главе 1 наследование было определено как система, при которой дочерние классы наследуют атрибуты и поведения от родительского класса. Однако это еще не все, что можно сказать о наследовании, и в этой главе мы подробнее ис- следуем его. Ранее отмечалось, что отношение наследования можно определить, придержи- ваясь простого правила: если вы можете сказать, что класс B является экзем- пляром класса А, то это отношение — хороший кандидат на то, чтобы быть от- ношением наследования. ОТНОШЕНИЕ «ЯВЛЯЕТСЯ ЭКЗЕМПЛЯРОМ» ___________________________________________ Одно.из.основных.правил.объектно-ориентированного.проектирования.заключает- ся.в.том,.что.открытое.наследование.представляется.отношением.«является.экзем- пляром»..В.случае.с.интерфейсами.вы.можете.добавить.правило.«ведет.себя.как». (implements)..Данные.(атрибуты),.которые.унаследованы,.—.это.«является»,.интер- фейсы,.которые.описывают.инкапсулируемые.поведения,.—.это.«функционирует. как»,..а.композиция.—.это.«имеет»..Грани,.однако,.довольно.размыты. Снова обратимся к примеру с классами млекопитающих, приводившемуся в главе 1. Взглянем на класс Dog . Он содержит несколько поведений, благо- даря которым совершенно ясно, что Dog противоположен классу Cat . В этом примере укажем два поведения для Dog : bark и pant . Таким образом, мы сможем создать класс Dog , содержащий два поведения наряду с двумя атрибутами (рис. 7.1). Глава.7..Наследование.и.композиция 142 Рис. 7.1. Диаграмма.класса.Dog Теперь предположим, что нам потребовалось создать класс GoldenRetriever Можно создать совершенно новый класс, содержащий те же поведения, которые имеются в классе Dog . При этом можно будет сделать следующий вполне обо- снованный вывод: GoldenRetriever является экземпляром Dog . В силу этого отношения у нас будет возможность наследовать атрибуты и поведения от Dog и использовать их в новом классе GoldenRetriever (рис. 7.2). Рис. 7.2. Класс.GoldenRetriever.наследует.от.класса.Dog Класс GoldenRetriever теперь содержит собственные поведения, а также все более общие поведения класса Dog . Это обеспечивает для нас значительные преимущества. Во-первых, когда мы создавали класс GoldenRetriever , нам не пришлось делать часть того, что и так уже было сделано, то есть переписывать методы bark и pant . Это позволяет сэкономить время, которое уходит на про- ектирование и написание кода, а также на тестирование и сопровождение. Методы bark и pant пишутся только один раз, и при условии, что они были надлежащим образом протестированы при создании класса Dog , их не придется опять основательно тестировать. Вместе с тем их потребуется заново протести- ровать при добавлении новых интерфейсов и т. д. Теперь полностью используем нашу структуру наследования и создадим второй класс, который будет дочерним по отношению к классу Dog . Назовем его LhasaApso . В то время как ретриверов разводят для того, чтобы использовать их 143 Наследование. . в качестве охотничьих поисковых собак, тибетские терьеры предназначены для охраны. Это не боевые собаки; у них острый нюх, и когда эти собаки чуют что-то необычное, они начинают лаять. Таким образом, мы можем создать наш класс LhasaApso , который будет наследовать от класса Dog точно так же, как это делал класс GoldenRetriever (рис. 7.3). Рис. 7.3. Класс.LhasaApso.наследует.от.класса.Dog ТЕСТИРОВАНИЕ НОВОГО КОДА ________________________________________________________ В.нашем.примере.с.классом. GoldenRetriever .методы. bark .и. pant .должны.быть. написаны,.протестированы.и.отлажены.при.создании.класса. Dog ..Теоретически.этот. код.теперь.надежен.и.готов.к.повторному.использованию.в.других.ситуациях..Одна- ко.тот.факт,.что.вам.не.нужно.переписывать.код,.не.означает,.что.вы.не.должны.его. протестировать..Конечно,.маловероятно,.что.у. GoldenRetriever .имеется.некая. особенность,.которая.тем.или.иным.образом.нарушит.код..Однако.вам.всегда.сле- дует.тестировать.новый.код..Каждое.новое.отношение.наследования.создает.кон- текст.для.использования.унаследованных.методов..Стратегия.полного.тестирования. должна.учитывать.каждый.из.таких.контекстов. Еще одно основное преимущество наследования состоит в том, что код для bark() и pant() располагается в одном месте. Допустим, возникла необходимость изменить код в методе bark() . Когда вы измените его в классе Dog , вам не при- дется изменять его в классах LhasaApso и GoldenRetriever Вы видите здесь проблему? На этом уровне кажется, что модель наследования очень хорошо работает. Однако как вы можете быть уверены в том, что все со- баки ведут себя именно так, как это отражает поведение, содержащееся в клас- се Dog ? В книге «Эффективное использование C++» Скотт Майерс приводит отличный пример дилеммы, касающейся проектирования с использованием наследования. Рассмотрим класс с именем Bird . Одной из наиболее узнаваемых особенностей Глава.7..Наследование.и.композиция 144 птиц является, конечно же, их способность летать. Таким образом, мы создадим класс с именем Bird , содержащий метод fly . Вам сразу же должна стать понятна проблема. Что нам делать с пингвином или страусом? Они тоже являются пти- цами, однако не умеют летать. Вы могли бы переопределить соответствующее поведение локально, однако метод по-прежнему будет иметь имя fly . Нет смыс- ла располагать методом с именем fly для класса птиц, которые не летают, а толь- ко ходят вперевалку, бегают или плавают. Это приводит к значительным проблемам. Например, в классе для пингвина со- держится метод fly , который пингвину может захотеться опробовать по вполне понятным причинам. Однако если бы на самом деле метод fly оказался переопре- делен и такое поведение, как полет, отсутствовало бы, то пингвин очень удивился бы вызовом метода fly , прыгнув через крутой обрыв. Представьте себе разочаро- вание пингвина, если вызов метода fly приведет к ходьбе вперевалку, а не к полету. В данной ситуации ходьба вперевалку не позволит справиться с поставленной задачей. Подумать только, что было бы, если бы такой код когда-нибудь оказался заложен в систему управления космического корабля. Это пример одного из прин- ципов SOLID — принципа подстановки Барбары Лисков, который мы обсудим в главе 12 «Принципы объектно-ориентированного проектирования SOLID». В нашем примере с Dog мы спроектировали этот класс таким образом, что все дочерние по отношению к нему классы содержат метод bark , отражающий спо- собность собак лаять. Однако некоторые собаки не лают. Например, собаки породы басенджи не умеют лаять. Несмотря на это, они издают звуки, похожие Рис. 7.4. Иерархия.классов.во.главе.с.Dog 145 Наследование. . на йодль. Как же нам следует пересмотреть то, что мы спроектировали? Как код выглядел бы после этого? На рис. 7.4 показан пример, демонстрирующий более корректный подход к моделированию иерархии класса Dog Обобщение и конкретизация Взглянем на объектную модель иерархии классов во главе с Dog . Мы начали с одного класса с именем Dog и определили общность между разными породами собак. Эту концепцию, иногда называемую обобщением-конкретизацией, также необходимо принимать во внимание при использовании наследования. Идея заключается в том, что по мере того, как вы спускаетесь по дереву наследования, все становится более конкретным. Самое общее располагается на верхушке дерева наследования. Если рассматривать наше дерево наследования Dog , класс с аналогичным названием располагается на его верхушке и является наиболее общей категорией. Разные породы — классы GoldenRetriever , LhasaApso и Basenji — являются наиболее конкретными. Идея наследования состоит в том, чтобы переходить от общего к частному, выделяя общность. Работая с моделью наследования Dog , мы начали выделять общность в поведе- нии, понимая при этом, что хотя поведение ретривера отличается от поведения тибетского терьера, у этих пород есть кое-что общее — например, для тех и дру- гих собак характерно учащенное дыхание. Кроме того, они лают. Затем мы осознали, что не все собаки лают — некоторые издают звуки, похожие на йодль. Таким образом, нам пришлось вынести поведение bark в отдельный класс BarkingDog . Поведение yodels мы поместили в класс YodelingDog . Однако мы осознали, что у всех лающих и нелающих собак все равно имеется кое-какая общность в поведении — все эти собаки учащенно дышат. Поэтому мы сохра- нили класс Dog и сделали так, чтобы от него наследовали классы BarkingDog и YodelingDog . Теперь Basenji может наследовать от YodelingDog , а у LhasaApso и GoldenRetriever есть возможность наследовать от BarkingDog Мы могли бы решить не создавать два отдельных класса BarkingDog и YodelingDog Тогда мы смогли бы реализовать bark и yodels как часть класса каждой отдель- ной породы, поскольку звуки, издаваемые собаками этих пород, различаются. Это лишь один пример проектных решений, которые придется принять. По- жалуй, наилучшим решением станет реализация bark и yodels как интерфейсов, о чем мы поговорим в главе 8. Паттерн проектирования, о котором говорится в главе 10 «Паттерны проекти- рования», может быть в этом случае неплохим выбором. Разработчик может не создавать разновидности класса Dog , скорее всего, он будет либо использовать класс Dog (который является реализацией IDog ), либо с помощью декоратора добавит поведения объекту Dog. Глава.7..Наследование.и.композиция 146 Проектные решения В теории лучший подход — выделение как можно большей общности. Однако, как и во всех задачах проектирования, слишком хорошо тоже нехорошо. Не- смотря на то что выделение как можно большей общности может быть макси- мально приближенным к реальной жизни, оно может не быть максимально приближенным к вашей модели. Чем большую общность вы выделяете, тем сложнее становится ваша система. Таким образом, вам необходимо решить головоломку: вы хотите, чтобы у вас была более точная модель или же менее сложная система? Вам придется сделать выбор в зависимости от вашей ситуации, и нет никаких жестких директив, которым необходимо следовать при принятии этого решения. В ЧЕМ КОМПЬЮТЕРЫ НЕ СИЛЬНЫ ___________________________________________________ Ясно,.что.компьютерная.модель.способна.лишь.примерно.отражать.реальные.ситу- ации..Компьютеры.сильны.в.решении.числовых.задач.большого.объема,.однако.не. так.хороши.в.выполнении.более.абстрактных.операций. Например, разбиение класса Dog на BarkingDog и YodelingDog моделирует ре- альную жизнь лучше, чем допущение, что все собаки лают, однако такой подход все немного усложняет. СЛОЖНОСТЬ МОДЕЛИ ________________________________________________________________ Добавив.еще.два.класса.на.данном.уровне.нашего.примера,.мы.не.усложним.все. настолько,.что.могло.бы.сделать.модель.неудачной..Однако.при.работе.с.более. крупными.системами,.когда.решения.подобного.рода.принимаются.много.раз,.слож- ность.быстро.повышается..Если.говорить.о.крупных.системах,.то.наилучшим.под- ходом.будет.сохранение.как.можно.большей.простоты. При проектировании вы будете сталкиваться с ситуациями, когда преимущества более точной модели не будут оправдывать повышение сложности. Предполо- жим, что вы являетесь собаководом и заключили субподрядный договор на создание системы, позволяющей отслеживать всех ваших собак. Системная модель, которая включает собак как лающих, так и издающих звуки, похожие на йодль, отлично работает. Однако, допустим, вы не разводите собак, издающих звуки, похожие на йодль. Пожалуй, у вас не будет необходимости усложнять систему разграничением собак по указанному параметру. Это сделает систему более простой и обеспечит требуемую вам функциональность. Решение о том, проектировать все так, чтобы система была менее сложной или же обладала большей функциональностью, должно быть сбалансированным. Основная цель заключается в том, чтобы всегда стремиться создать систему, которая будет гибкой, но не настолько сложной, что может рухнуть под соб- 147 Наследование. . ственной тяжестью. Что должно случиться, если вы добавите в проект собак, издающих звуки, похожие на йодль, уже позже? Текущие и будущие издержки тоже относятся к числу основных факторов, влияющих на такие решения. Несмотря на то что желание сделать систему более полной и гибкой может показаться уместным, добавленная в результате этого функциональность едва ли привнесет какие-либо преимущества — окупаемости инвестиций может не произойти. Например, расширили ли бы вы конструкцию своей системы Dog , чтобы включить в нее других представителей семейства псовых вроде гиен и лис (рис. 7.5)? Рис. 7.5. Расширенная.модель.Canine Если вы являетесь служителем зоопарка, то такая конструкция может оказать- ся целесообразной, однако если вы разводите и продаете домашних собак, рас- ширять класс Canine , вероятно, не потребуется. Как вы можете видеть, при проектировании всегда приходится принимать ком- промиссные решения. ПРИНЯТИЕ ПРОЕКТНЫХ РЕШЕНИЙ С УЧЕТОМ БУДУЩЕГО ____________________________ На.данном.этапе.вы.могли.бы.сказать.«Никогда.не.говори.“никогда”»..Несмотря.на. то.что.сейчас.вы,.возможно,.не.разводите.собак,.издающих.звуки,.которые.напо- минают.йодль,.когда-нибудь.в.будущем.у.вас.может.возникнуть.желание.заняться. этим..Если.вы.не.станете.сразу.проектировать.систему.с.учетом.возможности.раз- ведения.таких.собак,.то.в.дальнейшем.соответствующее.изменение.системы.обой- дется.намного.дороже..Это.еще.одно.из.многих.проектных.решений,.которые.вам. придется.принять..Вы,.вероятно,.могли.бы.переопределить.метод. bark() .для.того,. Глава.7..Наследование.и.композиция 148 чтобы.«превратить».его.в. yodels() ,.однако.результат.не.окажется.интуитивно.по- нятным,.поскольку.некоторые.люди.ожидают,.что.метод,.позволяющий.выполнять. соответствующее.действие,.будет.иметь.имя. bark() Композиция Вполне естественно представлять себе, что в одних объектах содержатся другие объекты. У телевизора есть тюнер и экран. У компьютера есть видеокарта, кла- виатура и накопитель. Компьютер можно считать объектом, но и флеш-диск тоже считается полноценным объектом. Вы могли бы открыть системный блок компьютера, снять жесткий диск и подержать его в руке. Более того, вы могли бы установить этот жесткий диск на другой компьютер. Утверждение, что этот накопитель является самостоятельным объектом, подкрепляется тем, что он может работать в разных компьютерах. Классический пример композиции объектов — автомобиль. Похоже, что во многих книгах, статьях и на подготовительных курсах автомобиль использует- ся как олицетворение композиции объектов. Большинство людей считают ав- томобильный сборочный конвейер, придуманный Генри Фордом, основным примером производства с использованием взаимозаменяемых деталей. Таким образом, кажется естественным, что автомобиль стал главным «исходным пун- ктом» при проектировании объектно-ориентированных программных систем. Почти всем людям показалось бы вполне естественным, что автомобиль имеет двигатель. Однако в состав автомобиля также входит много других объектов, включая колеса, руль и стереосистему (рис. 7.6). Во всех случаях, когда опреде- ленный объект состоит из других объектов, которые включены как объектные поля, новый объект называется составным, агрегированным или обобщенным. Рис. 7.6. Пример.композиции АГРЕГАЦИЯ, АССОЦИАЦИЯ И КОМПОЗИЦИЯ _________________________________________ На.мой.взгляд,.есть.только.два.способа.повторного.использования.классов.—.с.по- мощью.наследования.или.композиции..В.главе.9.мы.подробно.поговорим.о.компо- зиции,.в.частности.об.агрегации.и.ассоциации..В.этой.книге.я.считаю.агрегацию. и.ассоциацию.типами.композиции,.хотя.на.этот.счет.есть.разные.мнения. 149 Композиция. . Представление композиции на UML. Моделируя на UML тот факт, что в состав объекта «автомобиль» входит объект «руль», задействуем нотацию, показанную на рис. 7.7. Рис. 7.7. Представление.композиции.на.UML АГРЕГАЦИЯ, АССОЦИАЦИЯ И UML ____________________________________________________ В.этой.книге.агрегации.представлены.на.UML.линиями.с.ромбом,.например,.для. двигателя,.являющегося.частью.автомобиля..Ассоциации.обозначены.просто.линя- ми.(без.ромба),.например,.для.отдельной.клавиатуры,.обслуживающей.отдельный. системный.блок.компьютера. Обратите внимание, что на конце линии, соединяющей класс Car с классом SteeringWheel , имеется ромб на стороне класса Car . Это означает, что Car вклю- чает (содержит как часть) SteeringWheel Расширим этот пример. Допустим, ни один из объектов в этой конструкции не задействует наследование. Все объектные отношения являются строго отноше- ниями композиции, при этом есть ее разные уровни. Конечно, это упрощенный пример, а при проектировании автомобиля используется гораздо больше объ- ектов и объектных отношений. Однако эта конструкция призвана послужить простой иллюстрацией того, что представляет собой композиция. Скажем, автомобиль состоит из двигателя, стереосистемы и двери. СКОЛЬКО ДВЕРЕЙ И СТЕРЕОСИСТЕМ? _______________________________________________ Следует.отметить,.что.у.автомобиля.обычно.несколько.дверей..У.одних.автомобилей. их.две,.а.у.других.—.четыре..Вы.даже.можете.посчитать.пятой.дверью.ту,.что.рас- положена.сзади.у.автомобиля.с.кузовом.типа.«хэтчбэк»..В.том.же.духе.не.в.каждом. автомобиле.обязательно.есть.стереосистема..Мне.даже.доводилось.видеть.авто- мобили.с.двумя.отдельными.стереосистемами..Подобные.ситуации.подробно.рас- сматриваются.в.главе.9..Пока.же.для.нашего.примера.договоримся,.что.у.автомо- биля.есть.только.одна.дверь.(возможно,.это.особый.гоночный.автомобиль).и.одна. стереосистема. |