|
Программирование >> Поддержка объектно-ориентированного программирования
обеспечены значительной поддержкой со стороны транслятора и в общем случае поддаются статическому анализу. 12.2.1 Что представляют классы? По сути в системе бывают классы двух видов: [1 ] классы, которые прямо отражают понятия области приложения, т.е. понятия, которые использует конечный пользователь для описания своих задач и возможных решений; и [2] классы, которые являются продуктом самой реализации, т.е. отражают понятия, используемые разработчиками и программистами для описания способов реализации. Некоторые из классов, являющихся продуктами реализации, могут представлять и понятия реального мира. Например, программные и аппаратные ресурсы системы являются хорошими кандидатами на роль классов, представляющих область приложения. Это отражает тот факт, что систему можно рассматривать с нескольких точек зрения, и то, что с одной является деталью реализации, с другой может быть понятием области приложения. Хорошо спроектированная система должна содержать классы, которые дают возможность рассматривать систему с логически разных точек зрения. Приведем пример: [1 ] классы, представляющие пользовательские понятия (например, легковые машины и грузовики), [2] классы, представляющие обобщения пользовательских понятий (движущиеся средства), [3] классы, представляющие аппаратные ресурсы (например, класс управления памятью), [4] классы, представляющие системные ресурсы (например, выходные потоки), [5] классы, используемые для реализации других классов (например, списки, очереди, блокировщики) и [6] встроенные типы данных и структуры управления. В больших системах очень трудно сохранять логическое разделение типов различных классов и поддерживать такое разделение между различными уровнями абстракции. В приведенном выше перечислении представлены три уровня абстракции: [1 +2] представляет пользовательское отражение системы, [3+4] представляет машину, на которой будет работать система, [5+6] представляет низкоуровневое (со стороны языка программирования) отражение реализации. Чем больше система, тем большее число уровней абстракции необходимо для ее описания, и тем труднее определять и поддерживать эти уровни абстракции. Отметим, что таким уровням абстракции есть прямое соответствие в природе и в различных построениях человеческого интеллекта. Например, можно рассматривать дом как объект, состоящий из [1 ] атомов, [2] молекул, [3] досок и кирпичей, [4] полов, потолков и стен; [5] комнат. Пока удается хранить раздельно представления этих уровней абстракции, можно поддерживать целостное представление о доме. Однако, если смешать их, возникнет бессмыслица. Например, предложение Мой дом состоит из нескольких тысяч фунтов углерода, некоторых сложных полимеров, из 5000 кирпичей, двух ванных комнат и 1 3 потолков - явно абсурдно. Из-за абстрактной природы программ подобное утверждение о какой-либо сложной программной системе далеко не всегда воспринимают как бессмыслицу. В процессе проектирования выделение понятий из области приложения в класс вовсе не является 31 5 простой механической операцией. Обычно эта задача требует большой проницательности. Заметим, что сами понятия области приложения являются абстракциями. Например, в природе не существуют налогоплательщики , монахи или сотрудники . Эти понятия не что иное, как метки, которыми обозначают бедную личность, чтобы классифицировать ее по отношению к некоторой системе. Часто реальный или воображаемый мир (например, литература, особенно фантастика) служат источником понятий, которые кардинально преобразуются при переводе их в классы. Так, экран моего компьютера (Маккинтош) совсем не походит на поверхность моего стола, хотя компьютер создавался с целью реализовать понятие настольный , а окна на моем дисплее имеют самое отдаленное отношение к приспособлениям для презентации чертежей в моей комнате. Я бы не вынес такого беспорядка у себя на экране. Суть моделирования реальности не в покорном следовании тому, что мы видим, а в использовании реальности как начала для проектирования, источника вдохновения и как якоря, который удерживает, когда стихия программирования грозит лишить нас способности понимания своей собственной программы. Здесь полезно предостеречь: новичкам обычно трудно находить классы, но вскоре это преодолевается без каких-либо неприятностей. Далее обычно приходит этап, когда классы и отношения наследования между ними бесконтрольно множатся. Здесь уже возникают проблемы, связанные со сложностью, эффективностью и ясностью полученной программы. Далеко не каждую отдельную деталь следует представлять отдельным классом, и далеко не каждое отношение между классами следует представлять как отношение наследования. Старайтесь не забывать, что цель проекта -смоделировать систему с подходящим уровнем детализации и подходящим уровнем абстракции. Для больших систем найти компромисс между простотой и общностью далеко не простая задача. 12.2.2 Иерархии классов Рассмотрим моделирование транспортного потока в городе, цель которого достаточно точно определить время, требующееся, чтобы аварийные движущиеся средства достигли пункта назначения. Очевидно, нам надо иметь представления легковых и грузовых машин, машин скорой помощи, всевозможных пожарных и полицейских машин, автобусов и т.п. Поскольку всякое понятие реального мира не существует изолированно, а соединено многочисленными связями с другими понятиями, возникает такое отношение как наследование. Не разобравшись в понятиях и их взаимных связях, мы не в состоянии постичь никакое отдельное понятие. Также и модель, если не отражает отношения между понятиями, не может адекватно представлять сами понятия. Итак, в нашей программе нужны классы для представления понятий, но этого недостаточно. Нам нужны способы представления отношений между классами. Наследование является мощным способом прямого представления иерархических отношений. В нашем примере, мы, по всей видимости, сочли бы аварийные средства специальными движущимися средствами и, помимо этого, выделили бы средства, представленные легковыми и грузовыми машинами. Тогда иерархия классов приобрела бы такой вид: движущееся средство легковая машина аварийное средство грузовая машина полицейская машина машина скорой помощи пожарная машина машина с выдвижной лестницей Здесь класс Emergency представляет всю информацию, необходимую для моделирования аварийных движущихся средств, например: аварийная машина может нарушать некоторые правила движения, она имеет приоритет на перекрестках, находится под контролем диспетчера и т.д. На С++ это можно задать так: class Vehicle { /*...*/ }; class Emergency { /* */ }; class Car : public Vehicle { /*...*/ }; class Truck : public Vehicle { /*...*/ }; class Police car : public Car , public Emergency { ... class Ambulance : public Car , public Emergency { ... class Fire engine : public Truck , Emergency { ... class Hook and ladder : public Fire engine { ... Наследование - это отношение самого высокого порядка, которое прямо представляется в С++ и используется преимущественно на ранних этапах проектирования. Часто возникает проблема выбора: использовать наследование для представления отношения или предпочесть ему принадлежность. Рассмотрим другое определение понятия аварийного средства: движущееся средство считается аварийным, если оно несет соответствующий световой сигнал. Это позволит упростить иерархию классов, заменив класс Emergency на член класса Vehicle: движущееся средство (Vehicle {eptr}) легковая машина (Car) грузовая машина (Truck) полицейская машина (Police car) машина скорой помощи (Ambulance) пожарная машина (Fire engine) машина с выдвижной лестницей (Hook and ladder) Теперь класс Emergency используется просто как член в тех классах, которые представляют аварийные движущиеся средства: class Emergency { /*...*/ }; class Vehicle { public: Emergency* eptr; /*...*/ }; class Car : public Vehicle { /*...*/ }; class Truck : public Vehicle { /*...*/ }; class Police car : public Car { /*...*/ }; class Ambulance : public Car { /*...*/ }; class Fire engine : public Truck { /*...*/ }; class Hook and ladder : public Fire engine { /*...*/ }; Здесь движущееся средство считается аварийным, если Vehicle::eptr не равно нулю. Простые легковые и грузовые машины инициализируются Vehicle::eptr равным нулю, а для других Vehicle::eptr должно быть установлено в ненулевое значение, например: Car::Car() конструктор Car eptr = 0; Police car::Police car() конструктор Police car eptr = new Emergency; Такие определения упрощают преобразование аварийного средства в обычное и наоборот: void f(Vehicle* p) delete p->eptr; p->eptr = 0; больше нет аварийного движущегося средства ... p->eptr = new Emergency; оно появилось снова Так какой же вариант иерархии классов лучше? В общем случае ответ такой: Лучшей является
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |