Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Podbelsky_V_V_C_Bazovy_kurs.pdf
Скачиваний:
69
Добавлен:
02.06.2015
Размер:
1.73 Mб
Скачать

Включение, вложение и наследование классов

13.1.Включение объектов классов

Всоответствии с основной задачей, решаемой при проектировании программы, входящие в нее классы могут находиться в разных отношениях. Наиболее простое – отношение независимости классов, т. е. независимости порождаемых ими объектов. Более сложное – отношение включения, для которого используют названия “имеет” (has-a) и “включает”, иначе “является частью” (is-part-of).

Втеории объектно-ориентированного анализа различают две формы отношения включения – композицию и агрегацию.

При отношении композиции объекты одного класса или нескольких разных классов входят как поля в объект другого (включающего) класса. Таким образом включенные объекты не существуют без включающего их объекта.

При отношении агрегации объект одного класса объединяет уже существующие объекты других классов, т. е. и включающий объект, и включаемые в него объекты существуют в некотором смысле самостоятельно. При уничтожении включающего объекта входившие в него объекты сохраняются.

Рассмотрим на примерах особенности реализации на языке C# отношений композиции и агрегации.

Определим (программа 13_01.cs) класс «точка на плоскости»:

class Point

{

double x, y;

public double X { get { return x; } set { x = value; } } public double Y { get { return y; } set { y = value; } }

}

В классе закрытые поля double x, y определяют координаты точки. Свойства X и Y обеспечивают удобный доступ к координатам точки, представленной объектом класса Рoint. В

Включение, вложение и наследование классов

237

 

 

классе Рoint нет явно определенного конструктора, и компилятор добавляет конструктор умолчания – открытый конструктор без параметров. Координаты создаваемой точки по умолчанию получают нулевые значения.

Объекты класса Рoint можно по-разному включать в более сложные классы. Возьмем в качестве такого включающего класса класс Сircle, объект которого представляет «окружность на плоскости». Объект класса Рoint (точку) будем использовать в качестве центра окружности.

Начнем с композиции классов и, отложив объяснения, дадим такое определение класса:

class Сircle

{// Закрытые поля:

double rad; // Радиус окружности

Рoint centre = new Рoint(); // Центр окружности

// Свойство для радиуса окружности:

public double Rad { get { return rad; } set { rad = value;

} }

//Свойство для получения значения длины окружности:

public double Len { get { return 2*rad*Math.PI; } }

//Свойство для центра окружности:

public point Centre { get { return centre; } set { centre = value; } }

public void display()

{

Console.WriteLine("Centre: X={0}, Y={1}; Radius={2},

"+

"Length={3, 6:f2}", centre.X, centre.Y, this.rad,

Len);

}

}

В классе Circle два закрытых поля: double rad – радиус окружности и Point centre – ссылка на объект класса Point. Для инициализации этой ссылки используется выражение с операцией new, в котором выполняется явное обращение к конструктору класса Рoint. Тем самым при создании каждого объекта «окружность» всегда создается в виде его поля объект «точка», определяющий центр окружности.

238

Г л а в а 1 3

 

 

Три открытых свойства обеспечивают доступ к характеристикам объекта-окружности: Rad – радиус окружности, Len – длина окружности, Centre – центр окружности.

Вклассе определен открытый метод display(), выводящий координаты центра и значения других характеристик объекта, представляющего окружность.

Так как в классе Circle нет явно определенных конструкторов, то неявно создается конструктор без параметров, и поля определяемого с его помощью объекта получают значения по умолчанию.

Вследующей программе создан объект класса Circle. Затем

спомощью свойств классов Circle и Point изменены значения его полей. Метод display() выводит сведения о характеристиках объекта.

static void Main()

{

Circle rim = new Circle(); rim.Centre.X = 10; rim.Centre.Y = 20; rim.Rad = 3.0; rim.display();

}

Результат выполнения программы:

Centre: X=10, Y=20; Radius=3, Length= 18,85

Основное, на что следует обратить внимание, – в программе нет отдельно существующего объекта класса Point. Именно это является основным признаком композиции классов. Объект класса Point явно создается только при создании объекта класса Circle.

На рис. 13.1 приведена диаграмма классов, находящихся в отношении композиции. Конструкторы умолчания, которые добавлены в объявления классов автоматически, на схемах классов не показаны. Тот факт, что ссылка на объект класса Point является значением поля centre объекта класса Circle, никак явно не обозначен.

Включение, вложение и наследование классов

239

 

 

Рис. 13.1. Диаграмма композиции классов

Не изменяя класс Рoint, можно следующим образом построить класс «окружность на плоскости», используя агрегацию классов (программа 13_2.cs):

class Сircle

 

 

{

 

 

// Закрытые поля:

 

 

double rad;

// Радиус окружности

Рoint centre;

// Ссылка без инициализации

public Сircle(Рoint p, double rd)

// Конструктор

{

 

 

centre = p;

 

 

rad = rd;

 

 

}

public double Rad { ... } public double Len { ... } public point Centre { ... } public void display() { ... }

}

В тексте нового класса Сircle показаны полностью только объявления полей и конструктор, первый параметр которого

– ссылка на объект класса Рoint. Свойства и метод display() остались без изменений.

240

Г л а в а 1 3

 

 

При таком измененном определении класса Сircle для создания его объекта необходимо, чтобы уже существовал объект класса Рoint, с помощью которого в объекте будет определено значение поля centre.

Диаграмма классов, находящихся в отношении агрегации, (см. рис. 13.2), практически та же, что и диаграмма композиции. Только в классе Сircle явно присутствует конструктор общего вида.

Рис. 13.2. Диаграмма агрегации классов

В следующей программе (в методе Main) создан объект класса Рoint. Затем с помощью свойств X и Y изменены значения его полей. На основе этого объекта конструктор класса Сircle формирует объект “окружность на плоскости”. Метод display() выводит сведения о характеристиках построенного объекта.

static void Main()

{

Рoint pt = new Рoint(); pt.X = 10;

pt.Y = 20;

Сircle rim = new Сircle(pt,10); rim.display();

}

Включение, вложение и наследование классов

241

 

 

Результат выполнения программы:

Centre: X=10, Y=20; Radius=10, Length=62,83

Вотличие от композиции при агрегации в классе Сircle нет явной инициализации поля centre. Для обеспечения включения объекта класса Рoint в объект класса Сircle в классе Сircle явно определен конструктор, одним из параметров которого служит ссылка на объект класса Рoint. В теле конструктора значение этой ссылки присваивается полю centre класса Сircle.

13.2.Вложение классов

Вобъявление класса в качестве его члена может войти объявление типа. Таким типом может быть класс. Этот внутренний класс называют вложенным классом, а включающий его класс

внешним. Особенностью вложенного класса является то, что ему доступны все члены внешнего класса, даже если эти члены закрытые (private). Обычно вложенный класс вводится только для выполнения действий внутри внешнего класса и “не виден” вне включающего его класса. Однако вложенный класс может быть объявлен с модификатором public, и тогда он становится доступен везде, где виден внешний класс. Если открытый класс Nested вложен в класс Outside, то для внешнего обращения к вложенному классу следует использовать квалифицированное имя Outside.Nested.

Продемонстрируем синтаксис вложения классов на примере класса окружность (Circle), центр которой представляет объект вложенного класса Point. Чтобы возможности внешнего класса Circle были близки к возможностям уже рассмотренных классов, реализующих композицию и агрегацию, сделаем вложенный класс Point открытым. В следующей программе объявлен указанный класс Circle с вложенным классом Point.

// 13_03.cs вложение классов using System;

class Circle

{// Закрытые поля:

double rad; // Радиус окружности

Point centre = new Point(); // Центр окружности

242

Г л а в а 1 3

 

 

//Свойство для радиуса окружности: public double Rad { get { return rad; }

set { rad = value; } }

//Свойство для получения значения длины окружности:

public double Len { get { return 2 * rad * Math.PI; } }

//Свойство для центра окружности:

public Point Centre { get { return centre; } set { centre = value; } }

public void display()

{

Console.WriteLine("Centre: X={0}, Y={1}; " + "Radius={2}, Length={3,6:f2}",

centre.X, centre.Y, this.rad, Len);

}

public class Point

{

double x, y;

public double X { get { return x; } set { x = value; } } public double Y { get { return y; } set { y = value; } }

}// end of Point

}// end of Circle class Program

{

static void Main()

{

Circle rim = new Circle(); rim.Centre.X = 100; rim.Centre.Y = 200; rim.Rad = 30.0; rim.display();

Результат выполнения программы:

Centre: X=100, Y=200; Radius=30, Length=188,50

В классе Circle для инициализации поля center используется конструктор умолчания класса Point. Префикс «Circle.» при этом не требуется применять, хотя его использование не приведет к ошибке. То же самое относится и к обозначению типа свойства Centre. Нет явного определения конструкторов

Включение, вложение и наследование классов

243

 

 

и во внешнем классе. Поэтому в методе Main() для создания объекта, ассоциированного со ссылкой rim, используется конструктор умолчания Circle(). Для обращения к свойствам, определяющим центр окружности, потребовалось использовать имена с двойной квалификацией: rim.Centre.X и rim.Centre.Y.

В отличие от композиции и агрегации при вложении классов внутренний класс (не только объект) не существует независимо от внешнего. На диаграмме классов вложенный класс изображается именно внутри внешнего (рис.13.3).

Рис. 13.3. Диаграмма вложения классов

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]