Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++, страница 16
Описание файла
PDF-файл из архива "Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++", который расположен в категории "". Всё это находится в предмете "объектно-ориентированный анализ и проектирование" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 16 страницы из PDF
Данфорт и Томлинсон утверждают: «Абстрагирование данных создаетнепрозрачный барьер, скрывающий состояние и функции объекта; принцип наследования требуетоткрыть доступ и к состоянию, и к функциям объекта для производных объектов» [65]. Длялюбого класса обычно существуют два вида клиентов: объекты, которые манипулируют сэкземплярами данного класса, и подклассы-наследники. Лисков поэтому отмечает, чтосуществуют три способа нарушения инкапсуляции через наследование: «подкласс может получитьдоступ к переменным экземпляра своего суперкласса, вызвать закрытую функцию и, наконец,обратиться напрямую к суперклассу своего суперкласса» [66].
Различные языкипрограммирования по-разному находят компромисс между наследованием и инкапсуляцией;наиболее гибким в этом отношении является C++. В нем интерфейс класса может быть разделенна три части: закрытую (private), видимую только для самого класса; защищенную (protected),видимую также и для подклассов; и открытую (public), видимую для всех.Примеры иерархии: множественное наследование. В предыдущем примере рассматривалось одиночное наследование, когда подкласс FruitGrowingPlan был создан только изодного суперкласса Growingplan.
В ряде случаев полезно реализовать наследование отнескольких суперклассов. Предположим, что нужно определить класс, представляющийразновидности растений.class Plant {public:Plant(char* name, char* species);virtual ~Plant();void setDatePlanted(Day);virtual establishGrowingConditions(const Condition&);const char* name() const;const char* species() const;Day datePlantedt) const;protected:char* repName;char* repSpecies;Day repPlanted;private:…};Каждый экземпляр класса plant будет содержать имя, вид и дату посадки.
Кроме того,для каждого вида растений можно задавать особые оптимальные условия выращивания. Мыхотим, чтобы эта функция переопределялась подклассами, поэтому она объявлена виртуальнойпри реализации в C++. Три параметра объявлены как защищенные, то есть они будут доступны иклассу, и подклассам (закрытая часть спецификации доступна только самому классу).Изучая предметную область, мы приходим к выводу, что различные группыкультивируемых растений — цветы, фрукты и овощи, — имеют свои особые свойства,существенные для технологии их выращивания. Например, для цветов важно знать временацветения и созревания семян. Аналогично, время сбора урожая важно для абстракций фруктов иовощей.
Создадим два новых класса — цветы (Flower) и фрукты-овощи (FruitVegetable); ониоба наследуют от класса Plant. Однако некоторые цветочные растения имеют плоды! Для этойабстракции придется создать третий класс, FlowerFruitVegetable, который будет наследовать отклассов Flower и FruitVegetablePlant.Чтобы не было избыточности, в данном случае очень пригодится множественноенаследование. Сначала давайте опишем отдельно цветы и фрукты-овощи.class FlowerMixin {public:PlowerMixin(Day timeToFlower, Day timeToSeed);virtual ~`````FlowerMixin() ;Day timeToFlower() const;Day timeToSeed() const;protected:…};class FruitVegetableMixin {public:FruitVegetableMixin(Day timeToHarvest) ;virtual ~FruitVegetableMixin() ;Day timeToHarvest() const;protected:…};Мы намеренно описали эти два класса без наследования.
Они ни от кого не наследуют испециально предназначены для того, чтобы их подмешивали (откуда и имя Mixin) к другимклассам. Например, опишем розу:class Rose : public Plant, public FlowerMixin...А вот морковь:class Carrot : public Plant, public FruiteVegetableMixin {};В обоих случаях классы наследуют от двух суперклассов: экземпляры подкласса Roseвключают структуру и поведение как из класса Plant, так и из класса FlowerMixin.
И вот теперьопределим вишню, у которой товаром являются как цветы, так и плоды:class Cherry : public Plant,public FlowerMixin,FruitVegetableMixin...Множественное наследование — вещь нехитрая, но оно осложняет реализацию языковпрограммирования.
Есть две проблемы — конфликты имен между различными суперклассами иповторное наследование. Первый случай, это когда в двух или большем числе суперклассовопределено поле или операция с одинаковым именем. В C++ этот вид конфликта должен бытьявно разрешен вручную, а в Smalltalk берется то, которое встречается первым. Повторноенаследование, это когда класс наследует двум классам, а они порознь наследуют одному и тому жечетвертому. Получается ромбическая структура наследования и надо решить, должен ли самыйнижний класс получить одну или две отдельные копии самого верхнего класса? В некоторыхязыках повторное наследование запрещено, в других конфликт решается «волевым порядком», а вC++ это оставляется на усмотрение программиста. Виртуальные базовые классы используются длязапрещения дублирования повторяющихся структур, в противном случае в подклассе появятсякопии полей и функций и потребуется явное указание происхождения каждой из копий.Множественным наследованием часто злоупотребляют.
Например, сладкая вата — эточастный случай сладости, но никак не ваты. Применяйте ту же «лакмусовую бумажку»: если B неесть А, то ему не стоит наследовать от А. Часто плохо сформированные структуры множественногонаследования могут быть сведены к единственному суперклассу плюс агрегация других классовподклассом.Примеры иерархии: агрегация. Если иерархия «is а» определяет отношение «обобщение/специализация», то отношение «part of» (часть) вводит иерархию агрегации.
Вот пример.class Garden {public:Garden();virtual ~Garden();protected:Plant* repPlants[100];GrowingPlan repPlan;};Это — абстракция огорода, состоящая из массива растений и плана выращивания.Имея дело с такими иерархиями, мы часто говорим об уровнях абстракции, которыевпервые предложил Дейкстра [67]. В иерархии классов вышестоящая абстракция являетсяобобщением, а нижестоящая — специализацией. Поэтому мы говорим, что класс Flowerнаходится на более высоком уровне абстракции, чем класс Plant. В иерархии «part of» класснаходится на более высоком уровне абстракции, чем любой из использовавшихся при егореализации. Так класс Garden стоит на более высоком уровне, чем класс Plant.Агрегация есть во всех языках, использующих структуры или записи, состоящие изразнотипных данных. Но в объектно-ориентированном программировании она обретает новуюмощь: агрегация позволяет физически сгруппировать логически связанные структуры, анаследование с легкостью копирует эти общие группы в различные абстракции.В связи с агрегацией возникает проблема владения, или принадлежности объектов.
Внашем абстрактном огороде одновременно растет много растений, и от удаления или заменыодного из них огород не становится другим огородом. Если мы уничтожаем огород, растенияостаются (их ведь можно пересадить). Другими словами, огород и растения имеют свои отдельныеи независимые сроки жизни; мы достигли этого благодаря тому, что огород содержит не самиобъекты Plant, а указатели на них. Напротив, мы решили, что объект GrowingPlan внутреннесвязан с объектом Garden и не существует независимо.
План выращивания физически содержитсяв каждом экземпляре огорода и погибает вместе с ним. Подробнее про семантику владения мыбудем говорить в следующей главе.ТипизацияЧто такое типизация? Понятие типа взято из теории абстрактных типов данных. Дойчопределяет тип, как «точную характеристику свойств, включая структуру и поведение,относящуюся к некоторой совокупности объектов» [68]. Для наших целей достаточно считать, чтотермины тип и класс взаимозаменяемы.8 Тем не менее, типы стоит обсудить отдельно, посколькуони выставляют смысл абстрагирования в совершенно другом свете. В частности, мы утверждаем,что:Типизация — это способ защититься от использования объектов одного класса вместодругого, или по крайней мере управлять таким использованием.Типизация заставляет нас выражать наши абстракции так, чтобы язык программирования,используемый в реализации, поддерживал соблюдение принятых проектных решений.
Вегнерзамечает, что такой способ контроля существенен для программирования «в большом» [70].Идея согласования типов занимает в понятии типизации центральное место. Например,возьмем физические единицы измерения [71]. Деля расстояние на время, мы ожидаем получитьскорость, а не вес. В умножении температуры на силу смысла нет, а в умножении расстояния насилу — есть. Все это примеры сильной типизации, когда прикладная область накладывает правилаи ограничения на использование и сочетание абстракций.Примеры сильной и слабой типизации.
Конкретный язык программирования можетиметь сильный или слабый механизм типизации, и даже не иметь вообще никакого, оставаясьобъектно-ориентированным. Например, в Eiffel соблюдение правил использования типовконтролируется непреклонно, — операция не может быть применена к объекту, если она незарегистрирована в его классе или суперклассе.