Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
63
Добавлен:
29.02.2016
Размер:
198.14 Кб
Скачать

5.3 Абстрактные классы

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

Абстрактный класс служит только для порождения потомков. Как правило, в нем задается набор методов, которые каждый из потомков будет реализовывать по-своему. Абстрактные классы предназначены для представления общих понятий, которые предполагается конкретизировать в производных классах.

Абстрактный класс задает интерфейс для всей иерархии, при этом методам класса может не соответствовать никаких конкретных действий. В этом случае методы имеют пустое тело и объявляются со спецификаторомabstract.

Абстрактный класс может содержать и полностью определенные методы, в отличие от сходного с ним по предназначению специального вида класса, называемого ин­терфейсом. Интерфейсы рассматриваются в следующей главе.

Если в классе есть хотя бы один абстрактный метод, весь класс также должен быть описан как абстрактный, например:

abstract class Spirit

{

public abstract void Passport();

}

class Monster : Spirit

{

. . .

override public void Passport()

{

Console.WriteLine( "Monster {0} \t health = {1} ammo = {2}",

name, health, ammo );

}

. . .

}

class Daemon : Monster

{

. . .

override public void Passport()

{

Console.WriteLine(

"Daemon {0} \t health = {1} ammo = {2} brain = {3}",

Name, Health, Ammo, brain );

}

. . .

}

Абстрактные классы используются при работе со структурами данных, предна­значенными для хранения объектов одной иерархии, и в качестве параметров методов. Если класс, производный от абстрактного, не переопределяет все абст­рактные методы, он также должен описываться как абстрактный.

Можно создать метод, параметром которого является абстрактный класс. На место этого параметра при выполнении программы может передаваться объект любого производного класса. Это позволяет создавать полиморфные методы, работаю­щие с объектом любого типа в пределах одной иерархии. Полиморфизм в раз­личных формах является мощным и широко применяемым инструментом ООП.

Мы уже использовали полиморфизм в лабораторной работе № 16 для того, чтобы метод PrintArray мог работать с массивом любого типа.

5.4 Бесплодные классы

В С# есть ключевое слово sealed, позволяющее описать класс, от которого, в про­тивоположность абстрактному, наследовать запрещается:

sealed class Spirit

{

. . .

}

// class Monster : Spirit { ... } ошибка!

Большинство встроенных типов данных описано как sealed.Если необходимо ис­пользовать функциональность бесплодного класса, применяется не наследование, авложение, иливключение: в классе описывается поле соответствующего типа.

Вложение классов, когда один класс включает в себя поля, являющиеся класса­ми, является альтернативой наследованиюпри проектировании. Например, если есть объект «двигатель», а требуется описать объект «самолет», логично сделать двигатель полем этого объекта, а не его предком.

Поскольку поля класса обычно закрыты, возникает вопрос, как же пользоваться методами включенного объекта. Общепринятый способ состоит в том, чтобы описать метод объемлющего класса, из которого вызвать метод включенного класса. Такой способ взаимоотношений классов известен как модель бключения-делегирования. Пример приведен в листинге 4.

Листинг 4 Модель включения-делегирования

using System;

namespace ConsoleApplication

{

class Двигатель

{

public void Запуск()

{

Console.WriteLine( "вжжжж!!" );

}

}

class Самолет

{ public Самолет()

{

левый = new Двигатель();

правый = new Двигатель();

}

public void Запустить_двигатели()

{

левый.Запуск();

правый.Запуск();

}

Двигатель левый, правый;

}

class Class1

{ static void Main()

{

Самолет AH24_1 = new Самолет();

АН24_1.3апустить_двигатели();

}

}

}

Результат работы программы:

вжжжж!!

вжжжж!!

В методе Запустить_двигателизапрос на запуск двигателей передается, или, как принято говорить,делегируется вложенному классу.

В отличие от наследования, когда производный класс «является» (isа) разно­видностью базового, модель включения-делегирования реализует отношение «имеет» (has а). При проектировании классов следует выбирать модель, наибо­лее точно отражающую смысл взаимоотношений классов, например, моделируе­мых объектов предметной области.